Rhino Mocks - Stub .Expect 与 .AssertWasCalled [英] Rhino Mocks - Stub .Expect vs .AssertWasCalled

查看:40
本文介绍了Rhino Mocks - Stub .Expect 与 .AssertWasCalled的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我知道 Rhino Mocks 中的新 AAA 语法有很多混乱,但我必须说实话,从我目前所见,我喜欢.它读起来更好,并且节省了一些按键.

OK, I know there has been a lot of confusion over the new AAA syntax in Rhino Mocks, but I have to be honest, from what I have seen so far, I like. It reads better, and saves on some keystrokes.

基本上,我正在测试一个 ListController,它基本上负责一些事情的列表 :) 我已经创建了一个最终将成为 DAL 的接口,这当然是暂时存根.

Basically, I am testing a ListController which is going to basically be in charge of some lists of things :) I have created an interface which will eventually become the DAL, and this is of course being stubbed for now.

我有以下代码:

(manager是被测系统,data是存根数据接口)

(manager is the system under test, data is the stubbed data interface)

    [Fact]
    public void list_count_queries_data()
    {
        data.Expect(x => x.ListCount(1));
        manager.ListCount();
        data.VerifyAllExpectations();
    }

此测试的主要目的是确保管理器实际上是在查询 DAL.请注意,DAL 实际上甚至不在那里,因此没有真正"的价值回来..

The main aim of this test is to just ensure that the manager is actually querying the DAL. Note that the DAL is not actually even there, so there is no "real" value coming back..

但是,这是失败的,因为我需要更改期望以具有返回值,例如:

However, this is failing since I need to change the expectation to have a return value, like:

        data.Expect(x => x.ListCount(1)).Return(1);

这将运行良好,并且测试将通过,然而 - 令我困惑的是,此时返回值意味着没有.我可以把它改成 100、50、42,不管怎样,测试总是会通过的?

This will then run fine, and the test will pass, however - what is confusing me is that at this point in time, the return value means nothing. I can change it to 100, 50, 42, whatever and the test will always pass?

这让我很紧张,因为测试应该是明确的,如果不满足预期条件,测试应该完全失败,对吗?

This makes me nervous, because a test should be explicit and should totally fail if the expected conditions are not met right?

如果我将测试更改为(1"是计数链接到的预期 ID):

If I change the test to (the "1" is the expected ID the count is linked to):

    [Fact]
    public void list_count_queries_data()
    {
        manager.ListCount();
        data.AssertWasCalled(x => x.ListCount(1));
    }

一切都很好,如果我将其头部的测试切换到 AssertWasNotCalled,它会按预期失败.. 我也认为它读起来好多了,更清楚正在测试的内容和最重要的是按预期通过和失败!

It all passes fine, and if I switch the test on it's head to AssertWasNotCalled, it fails as expected.. I also think it reads a lot better, is clearer about what is being tested and most importantly PASSES and FAILS as expected!

那么,我在第一个代码示例中是否遗漏了什么?您对在存根上进行断言有何想法?(有一些有趣的讨论 这里,我个人喜欢此回复.

So, am I missing something in the first code example? What are your thoughts on making assertions on stubs? (there was some interesting discussion here, I personally liked this response.

推荐答案

您的测试要达到什么目的?

您要验证什么行为或状态?具体来说,您是在验证协作者(数据)是否正在调用其 ListCount 方法(基于交互的测试),还是只想让 ListCount 返回一个固定值到在其他地方验证结果的同时推动被测课程(传统的基于状态的测试)?

What behaviour or state are you verifying? Specifically, are you verifying that the collaborator (data) is having its ListCount method called (interaction based testing), or do you just want to make ListCount return a canned value to drive the class under test while verifying the result elsewhere (traditional state based testing)?

如果你想设置一个期望,使用一个模拟和一个期望:使用 MockRepository.CreateMock()myMock.Expect(x => x.ListCount())

If you want set an expectation, use a mock and an expectation: Use MockRepository.CreateMock<IMyInterface>() and myMock.Expect(x => x.ListCount())

如果要存根方法,请使用 MockRepository.CreateStub()myStub.Stub(x => x.ListCount()).

If you want to stub a method, use MockRepository.CreateStub<IMyInterface>() and myStub.Stub(x => x.ListCount()).

(旁白:我知道你可以使用 stub.AssertWasCalled() 来实现与 mock.Expect 几乎相同的事情,并且可以说是更好的阅读语法,但我只是深入研究了 mocks 和 stubs 之间的区别).

(aside: I know you can use stub.AssertWasCalled() to achieve much the same thing as mock.Expect and with arguably better reading syntax, but I'm just drilling into the difference between mocks & stubs).

Roy Osherove 对模拟和存根有很好的解释.

请发布更多代码!

我们需要全面了解您如何创建存根(或模拟)以及如何将结果用于被测类.ListCount 有输入参数吗?如果有,它代表什么?您是否关心它是否被调用 某个值?你关心 ListCount 返回某个值吗?

We need a complete picture of how you're creating the stub (or mock) and how the result is used with respect to the class under test. Does ListCount have an input parameter? If so, what does it represent? Do you care if it was called with a certain value? Do you care if ListCount returns a certain value?

正如 Simon Laroche 指出的那样,如果 Manager 实际上没有对 ListCount 的模拟/存根返回值做任何事情,那么测试将不会因此通过或失败.所有测试都期望调用模拟/存根方法——仅此而已.

As Simon Laroche pointed out, if the Manager is not actually doing anything with the mocked/stubbed return value of ListCount, then the test won't pass or fail because of it. All the test would expect is that the mocked/stubbed method is called -- nothing more.

为了更好地理解这个问题,请考虑三个信息,你很快就会明白这一点:

To better understand the problem, consider three pieces of information and you will soon figure this out:

  1. 正在测试什么
  2. 在什么情况下?
  3. 预期的结果是什么?

比较:基于交互的模拟测试.模拟调用测试.

Compare: Interaction based testing with mocks. The call on the mock is the test.

[Test]
public void calling_ListCount_calls_ListCount_on_DAL()
{
   // Arrange
   var dalMock = MockRepository.Mock<IDAL>();
   var dalMock.Expect(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   manager.ListCount();

   // Assert -- Test is 100% interaction based
   dalMock.VerifyAllExpectations();   
}

使用存根进行基于状态的测试.存根驱动测试,但不是预期的一部分.

State based testing with a stub. The stub drives the test, but is not a part of the expectation.

[Test]
public void calling_ListCount_returns_same_count_as_DAL()
{
   // Arrange
   var dalStub = MockRepository.Stub<IDAL>();
   var dalStub.Stub(x => x.ListCount()).Returns(1);
   var manager = new Manager(dalMock);

   // Act
   int listCount = manager.ListCount();

   // Assert -- Test is 100% state based
   Assert.That(listCount, Is.EqualTo(1),
       "count should've been identical to the one returned by the dal!");
}

我个人更喜欢尽可能基于状态的测试,尽管使用 告诉,不要问,因为你不会有任何暴露的状态来验证!

I personally favour state-based testing where at all possible, though interaction based testing is often required for APIs that are designed with Tell, Don't Ask in mind, as you won't have any exposed state to verify against!

API 混乱.模拟不是存根.还是他们?

犀牛模拟中模拟和存根之间的区别是模糊的.传统上,存根并不意味着有期望——所以如果你的测试替身没有调用它的方法,这不会直接导致测试失败.

The distinction between a mock and a stub in rhino mocks is muddled. Traditionally, stubs aren't meant to have expectations -- so if your test double didn't have its method called, this wouldn't directly cause the test to fail.

... 然而,Rhino Mocks API 功能强大,但令人困惑,因为它允许您对存根设置期望,这与公认的术语背道而驰.介意,我也不怎么想这些术语.在我看来,如果消除区别并且调用测试替身的方法设置角色会更好.

... However, the Rhino Mocks API is powerful, but confusing as it lets you set expectations on stubs which, to me, goes against the accepted terminology. I don't think much of the terminology, either, mind. It'd be better if the distinction was eliminated and the methods called on the test double set the role, in my opinion.

这篇关于Rhino Mocks - Stub .Expect 与 .AssertWasCalled的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆