如何与抛出的异常同时断言模拟状态

时间:2013-10-05 20:42:09

标签: c# tdd moq

我正在关注TDD并遇到一个问题,如果我让一个测试成功,另外两个因为抛出异常而失败。好吧,我想抛出异常,但我也想验证其他行为。例如:

public class MyTests {

    [Fact]
    public void DoSomethingIsCalledOnceWhenCheckerIsTrue() 
    {
        var checker = new Mock<IChecker>();
        var doer = new Mock<IDoer>();

        checker.Setup(x => x.PassesCheck).Returns(true);
        var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);

        sut.CheckAndDo();

        checker.VerifyGet(x => x.PassesCheck, Times.Once());
        doer.Verify(x => x.Do(),Times.Once());
    }

    [Fact]
    public void DoSomethingIsNeverCalledWhenCheckerIsFalse() 
    {
        var checker = new Mock<IChecker>();
        var doer = new Mock<IDoer>();

        checker.Setup(x => x.PassesCheck).Returns(false);
        var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);

        sut.CheckAndDo();

        doer.Verify(x => x.Do(),Times.Never());
    }

    [Fact]
    public void ThrowCheckDidNotPassExceptionWhenCheckDoesNotPass()
    {
        var checker = new Mock<IChecker>();
        var doer = new Mock<IDoer>();

        checker.Setup(x => x.PassesCheck).Returns(false);
        var sut = new ThingThatChecksAndDoes(checker.Object,doer.Object);

        Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
    }

}

我接近这个有什么选择?什么,如果有的话,将是“首选”的选择?

2 个答案:

答案 0 :(得分:1)

您的第一次和第二次测试通过。然后当你添加第三个测试时,其余的测试都会失败!。

使用TDD

  

“避免更改传递的现有测试。而是添加新测试。   仅在用户要求更改时才更改现有测试。“

我还假设你的SUT(被测系统)如下

  public void CheckAndDo() {
        var b = _checker.PassesCheck;
        if (b) {
            _doer.Do();
        }

        throw new CheckDidNotPassException();
    }

在您的SUT中,当您抛出一个新的异常时,显然它会影响您执行执行逻辑的其余行为。

所以这里的选项是改变现有的测试。

给它一个命名良好的测试方法,并断言异常和验证。

    [Test]
    public void CheckAndDo_WhenPassesCheckTrue_DoCalledOnlyOnceAndThrowsCheckDidNotPassException()
    {
        var checker = new Mock<IChecker>();
        var doer = new Mock<IDoer>();

        checker.Setup(x => x.PassesCheck).Returns(true);
        var sut = new ThingThatChecksAndDoes(checker.Object, doer.Object);

        Assert.Throws<CheckDidNotPassException>(() => { sut.CheckAndDo(); });
        doer.Verify(x => x.Do(), Times.Once());
    }

您需要考虑的其他事项很少:

一个。 TDD产生良好的单元测试。良好的手段,可读,可维护和值得信赖的单元测试。    您的测试方法名称和对SUT的调用命名不佳。我想这只是针对demo / Stackoverflow问题。但我建议将来你提供一个真实世界的例子,除了“Do”“Something”之外的真实姓名    从TDD的角度来看,模糊名称并没有帮助,因为您根据需求设计了小型系统。

湾发布正确的代码。 在第一次测试中,你传递了模拟类型

   var checker = new Mock<IChecker>();
   var doer = new Mock<IDoer>();
   var sut = new ThingThatChecksAndDoes(checker, doer);

你应该传递实例,即(checker.Object)

答案 1 :(得分:0)

当我测试类似的方法时

  • 我没有写测试,x.Do()没有被调用
  • 我检查是否抛出了异常,并且在一次测试中没有调用x.Do(),因为这两个断言与同一个流相关。