代码之家  ›  专栏  ›  技术社区  ›  Gishu

如何避免设置重复代码与记录重放模式的Rhino模拟?

  •  3
  • Gishu  · 技术社区  · 15 年前

    这是一个使用犀牛模型的绿色测试套件。

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

    现在,为了在另一个设备中进行绿色测试,我必须对ctr做一个微小的更改—订阅打印机接口中的一个事件。这导致上述测试夹具中的所有测试都变红。

    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认为您已经设置了一个事件订阅,作为另一种期望。然而,这个修复意味着在每个测试中(一些)重复。 每个测试通常在调用replayal之前添加一些期望值。

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

    • 然而,这是一个正常的场景,例如,在ModelViewPresenter模式中,我很好奇是否有推荐的方法可以做到这一点?
    • 另外,我不喜欢测试夹具中的多个测试由于外部测试驱动的更改而失败的方式?我在测试设计气味国家吗?
    2 回复  |  直到 15 年前
        1
  •  3
  •   Kenneth Xu    15 年前

    我同意Mark使用显式设置而不是隐式设置。但是关于犀牛模型的使用,你试过下面的方法吗?你可以把一个模拟放在回放模式临时和恢复录制以后。类似:

    
        SetupResult.For(_mockPrinter...);
        _mocksRepo.Replay(_mockPrinter);
        _testSubject = new CrashTestDummy(DUMMY_NAME, _mockPrinter, _mockLogger);
        _mocksRepo.BackToRecord(_mockPrinter, BackToRecordOptions.None);
    
        2
  •  1
  •   Mark Seemann    15 年前

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

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

    重要的是要认识到,当涉及到XUnit测试模式时, 固定装置 意思和努尼特不同。它不是一个测试类,而是包含 在运行测试系统(SUT)之前,必须在测试用例中作为前提条件的所有内容 .

    使用设置方法(如beforeeachtest方法)来设置夹具是很常见的,但还有其他方法,我稍后将回到这里。

    通用夹具的问题是,您试图用相同夹具覆盖过多的具有稍微不同前提的特定测试用例。这是您现在观察测试之间这种相互依赖性的一个根本原因。

    为了使问题复杂化,努尼特的特殊之处在于它可以重复使用 相同的 跨多个测试用例的特定测试类的实例,这样状态就可以从一个测试保持到另一个测试。所有其他XUnit框架都为每个测试用例创建一个新的测试类实例,这样这种类型的问题就不那么常见了。

    这使我回到了在设置方法中设置fixture的替代方法(即 隐式设置 ):编写一个方法或对象,封装夹具并将其创建为每个测试用例中的第一行代码。这也允许您通过参数化这个夹具设置代码,在不同的测试用例之间稍微改变夹具。

    Here's an example of how I usually do this .