如何避免使用Rhino Mocks的记录重放模式进行设置代码重复?

时间:2009-09-30 06:07:27

标签: unit-testing tdd rhino-mocks

这是一个使用Rhino Mocks的绿色测试套件。

[SetUp]
  public void BeforeEachTest()
  {
     _mocksRepo = new MockRepository();
     _mockBank = _mocksRepo.StrictMock<IBank>();
     //_mockPrinter = _mocksRepo.StrictMock<IPrinter>();
     _mockPrinter = _mocksRepo.DynamicMock<IPrinter>();
     _mockLogger = _mocksRepo.StrictMock<ILog>();

     _testSubject = new CrashTestDummy(DUMMY_NAME, _mockPrinter, _mockLogger);
  }

  [TearDown]
  public void AfterEachTest()
  {
     _mocksRepo.ReplayAll(); // 2nd call to ReplayAll does nothing. Safeguard check
     _mocksRepo.VerifyAll();
  }

  [Test]
  public void Test_ConstrainingArguments()
  {
     _mockPrinter.Print(null);
     LastCall.Constraints(Text.StartsWith("The current date is : "));
     _mocksRepo.ReplayAll();

     _testSubject.PrintDate();
  }

现在要在另一个灯具中进行绿色测试,我不得不对ctor做一点改动 - 订阅打印机界面中的事件。这导致上述测试夹具中的所有测试都变为红色。

public CrashTestDummy(string name, IPrinter namePrinter, ILog logger)
      {
         _printer = namePrinter;
         _name = name;
         _logger = logger;

         _printer.Torpedoed += KaboomLogger;   // CHANGE
      }

NUnit错误标签显示

LearnRhinoMocks.Rhino101.Test_ConstrainingArguments:
TearDown : System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
  ----> Rhino.Mocks.Exceptions.ExpectationViolationException : IPrinter.add_Torpedoed(System.EventHandler`1[LearnRhinoMocks.MyEventArgs]); Expected #1, Actual #0.

解决此问题的方法是从测试中的Setup()行下方的ReplayAll()处移动创建测试主题的行。 Rhino mocks认为你已经设置了一个事件订阅作为期望。但是,此修复意味着(某些)每次测试都会重复。 在调用ReplayAll之前,每个测试通常会增加一些期望。

我知道这是一个特定的场景,涉及测试主题ctor中的事件订阅。

  • 然而,这是正常情况,例如在ModelViewPresenter模式中,我很想知道是否有推荐的方法来做到这一点?
  • 另外,我不喜欢测试夹具中的多个测试由于外部测试驱动的更改而失败的方式?我是测试设计的嗅觉国家吗?

2 个答案:

答案 0 :(得分:3)

我同意Mark使用显式设置而不是隐式设置。但是在使用RhinoMocks时,您是否尝试过以下内容。你可以暂时将模拟放在重播模式中,然后再继续录制。类似的东西:


    SetupResult.For(_mockPrinter...);
    _mocksRepo.Replay(_mockPrinter);
    _testSubject = new CrashTestDummy(DUMMY_NAME, _mockPrinter, _mockLogger);
    _mocksRepo.BackToRecord(_mockPrinter, BackToRecordOptions.None);

答案 1 :(得分:1)

根据xUnit Test Patterns,你确实是在测试设计嗅觉国家:)

问题是一种名为General Fixture的测试气味,这意味着运行时环境总是以相同的方式配置在许多不同的测试中。

重要的是要意识到,当谈到xUnit测试模式时,术语 Fixture 意味着与NUnit不同的东西。它不是一个测试类,而是涵盖在运行被测系统(SUT)之前必须作为测试用例中的前提条件的所有内容的概念

使用诸如BeforeEachTest方法之类的设置方法设置Fixture是很常见的,但还有其他方法,我很快就会回过头来。

通用夹具的问题在于,您尝试使用相同的夹具覆盖太多具有略微不同前提条件的特定测试用例。这是您现在观察测试之间相互依赖性的根本原因之一。

为了解决这个问题,NUnit的特殊之处在于它在多个测试用例中重用了特定测试类的相同实例,因此该状态可能会从一个测试延伸到另一个测试。所有其他xUnit框架为每个测试用例创建测试类的新实例,因此这种类型的问题不太常见。

这让我回到了在设置方法(所谓的隐式设置)中设置Fixture的替代方法:编写封装Fixture并将其创建为第一行的方法或对象每个测试用例中的代码。这也允许您通过参数化此Fixture设置代码,从测试用例到测试用例略微改变Fixture。

Here's an example of how I usually do this