【问题标题】:c# Rhino mocks - Is this an appropriate use of mocks?c# Rhino mocks - 这是对模拟的适当使用吗?
【发布时间】:2009-12-30 19:35:30
【问题描述】:

请原谅我的无知。我正在努力学习 Rhino。

public Foo(Stream stream)
{
    if (stream == null) throw new ArgumentNullException("woot");
    if (!stream.CanRead) throw new NotSupportedException("sporkish");
    if (!stream.CanSeek) throw new NotSupportedException("monkey");
}

我想通过对这些异常进行测试来使用 NUnit 测试来测试此功能。这是对模拟对象的适当使用,还是我实际上需要创建一个特殊的继承类 Stream?如果模拟是合适的,我该如何使用 Rhino 来做到这一点?我可以弄清楚如何从函数中返回虚拟值(我认为),但不是属性。

【问题讨论】:

    标签: c# unit-testing mocking rhino-mocks


    【解决方案1】:

    你可以创建一个Stream的mock,表示它不能读取也不能搜索,如下

    MockRepository mocks = new MockRepository();
    
    Stream mockStream = mocks.StrictMock<Stream>();
    
    Expect.Call(mockStream.CanRead).Return(false);
    Expect.Call(mockStream.CanSeek).Return(false);
    
    mocks.ReplayAll();
    
    // Perform the unit test.
    
    mocks.VerifyAll();
    

    关于模拟的一些值得记住的事情:

    1. 模拟不仅仅是创建返回虚拟值的对象。一个好的模拟框架测试一个类的特定成员是否已被访问。这使您可以测试以查看您正在测试的类是否对依赖对象进行了正确的调用。在上面的示例中,如果在调用 VerifyAll() 时您还没有读取 both CanReadCanSeek 的值,则会引发异常以使您的测试失败。李>
    2. 在针对接口进行测试时,模拟最有用。您可以在特定类型中覆盖的行为越少,模拟的效果就越差。对于Stream,您可以覆盖您关心的属性,因此您可以轻松实现创建模拟的目标。如果您想模拟一个非虚拟/可覆盖的属性,您将面临更艰巨的任务。

    对于您的场景,为了测试抛出的三个异常,您需要创建两个单独的模拟来访问所有代码路径:第一个断言失败的模拟 (!stream.CanRead) 和一个通过第一个断言但第二个断言失败的断言 (!stream.CanSeek)。

    【讨论】:

    • 我知道我现在做错了什么。我试图在 .Return(false) 调用之前使用 PropertyBehavior。我想我误解了 PropertyBehavior 的用法。我还是菜鸟。 :)
    【解决方案2】:

    这是对 Mocks 的恰当使用。您将需要三个 Mock 对象。一种没有stream.CanRead,一种没有stream.CanSeek,一种同时有(测试是否成功)。

    不要忘记,这可能涉及将您正在使用的Stream 的功能分解到一个单独的接口中(以便您可以从该接口构建您的模拟对象)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多