如何使用xUnit、SubSpec和FakeItEasy测试抛出的异常

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());

非常感谢


不确定这是否有帮助,但你是否查看了SubSpec的文档,例如https://bitbucket.org/johannesrudolph/subspec/src/a35fcc8ae1f6/test/SubSpec.Tests/ContextSetupTeardownBehavior.cs?此外,这些是基于BDD /规范的测试,而不是单元测试。如果包括BDD标签,您可能会得到更好的受众。 - Spock
3个回答

12

我从未听说过FakeItEasy或SubSpec(你的测试看起来相当奇特,所以我可能会检查一下它们 :))。 但是,我确实使用xUnit,因此这可能会有所帮助:

我使用Record.Exception与Assert.ThrowsDelegate

所以可以像这样写:

    [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);
    }
希望这有所帮助。

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()
     );

或者更好的办法是,将SubSpec替换为xBehave.net,并引入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());

5
这是在FakeItEasy中执行的一种方法。
Action act = () => someObject.SomeMethod(someArgument);
act.ShouldThrow<Exception>();

2
我收到了一个“Action does not contain a definition for ShouldThrow...”的错误提示。我需要包含哪个引用/程序集? - Emmanuel John
act.Should().Throw<Exception>(); - duyn9uyen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接