14

単体テストには xUnit、SubSpec、FakeItEasy を使用しています。これまでに、次のような肯定的な単体テストをいくつか作成しました。

"Given a Options presenter"
    .Context(() =>
        presenter = new OptionsPresenter(view,
                                         A<IOptionsModel>.Ignored,
                                         service));

"with the Initialize method called to retrieve the option values"
    .Do(() => 
        presenter.Initialize());

"expect the view not to be null"
    .Observation(() =>
        Assert.NotNull(view));

"expect the view AutoSave property to be true"
    .Observation(() => Assert.True(view.AutoSave));

しかし今、いくつかの否定的な単体テストを作成し、特定のメソッドが呼び出されず、例外がスローされることを確認したいと考えています

例えば

"Given a Options presenter"
    .Context(() =>
        presenter = new OptionsPresenter(view,
                                         A<IOptionsModel>.Ignored,
                                         service));

"with the Save method called to save the option values"
    .Do(() => 
        presenter.Save());

"expect an ValidationException to be thrown"
    .Observation(() =>
        // TODO 
     );

"expect an service.SaveOptions method not to be called"
    .Observation(() =>
        // TODO 
     );

FakeItEasy には MustNotHaveHappened 拡張メソッドがあり、xUnit には Assert.Throws メソッドがあることがわかります。

しかし、どうすればすべてをまとめることができますか?

テストしたい例外は、Save メソッドが呼び出されたときに発生するはずです。したがって、presenter.Save() メソッド呼び出しの周りに Assert.Throws メソッドをラップする必要があると思いますが、presenter.Save メソッドは .Do(() => ... で呼び出す必要があると思いました。

私の単体テストが以下のように見えるべきか、それとも何か他のように見えるべきか教えてください。

"Given a Options presenter"
    .Context(() =>    
        presenter = new OptionsPresenter(view,
                                         model,
                                         service));

"expect the Presenter.Save call to throw an Exception"
    .Observation(() =>
        Assert.Throws<FluentValidation.ValidationException>(() => presenter.Save()));

"expect the Service.SaveOptions method not to be called"
    .Observation(() =>
        A.CallTo(() => service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened());

どうもありがとう

4

3 に答える 3

12

FakeItEasy や SubSpec については聞いたことがありません (あなたのテストはかなりファンキーに見えるので、これらをチェックするかもしれません :))。ただし、私は xUnit を使用しているので、これが役立つ場合があります。

私は、Assert.ThrowsDelegate で Record.Exception を使用します。

次のようなものです:

    [Fact]
    public void Test()
    {
        // Arange

        // Act
        Exception ex = Record.Exception(new Assert.ThrowsDelegate(() => { service.DoStuff(); }));

        // Assert
        Assert.IsType(typeof(<whatever exception type you are looking for>), ex);
        Assert.Equal("<whatever message text you are looking for>", ex.Message);
    }

それが役立つことを願っています。

于 2012-12-19T15:44:43.317 に答える
7

私は次のようにします:

"Given a Options presenter"
    .Context(() =>
        presenter = new OptionsPresenter(view,
                                         (IOptionsModel)null,
                                         service));

"with the Save method called to save the option values"
    .Do(() => 
        exception = Record.Exception(() => presenter.Save()));

"expect an ValidationException to be thrown"
    .Observation(() =>
        Assert.IsType<ValidationException>(exception)
     );

"expect an service.SaveOptions method not to be called"
    .Observation(() =>
        A.CallTo(() => service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened()
     );

またはさらに良いことに、xBehave.net の SubSpec を切り替えてFluentAssertionsを導入します:-

"Given an options presenter"
    .x(() => presenter = new OptionsPresenter(view, (IOptionsModel)null, service));

"When saving the options presenter"
    .x(() => exception = Record.Exception(() => presenter.Save()));

"Then a validation exception is thrown"
    .x(() => exception.Should().BeOfType<ValiationException>());

"And the options model must not be saved"
    .x(() => A.CallTo(() =>
        service.SaveOptions(A<IOptionsModel>.Ignored)).MustNotHaveHappened());
于 2013-02-16T11:06:46.563 に答える