Unit testing 如何使用Rhino Mock模拟本地函数调用?

Unit testing 如何使用Rhino Mock模拟本地函数调用?,unit-testing,rhino-mocks,Unit Testing,Rhino Mocks,以下是我的情况: 我想测试“HasSomething()”函数,它位于以下类中: public class Something { private object _thing; public virtual bool HasSomething() { if (HasSomething(_thing)) return true; return false; } p

以下是我的情况: 我想测试“HasSomething()”函数,它位于以下类中:

public class Something
{
      private object _thing;

      public virtual bool HasSomething()
      {
           if (HasSomething(_thing))
              return true;
           return false;
      }

      public virtual bool HasSomething(object thing)
      {
           ....some algo here to check on the object...
           return true;
      }
}
所以,我写我的测试是这样的:

    public void HasSomethingTest1()
    {
        MockRepository mocks = new MockRepository();

        Something target = mocks.DynamicMock(typeof(Something)) as Something;

        Expect.Call(target.HasSomething(new Object())).IgnoreArguments().Return(true);

        bool expected = true;
        bool actual;
        actual = target.HasSomething();

        Assert.AreEqual(expected, actual);
    }
我的试卷写对了吗? 请帮助我,因为我甚至不能得到预期的结果。“HasSomething(object)”不能用那种方式来模仿。它没有将我的期望值设置为“真”


谢谢。

回应OP的“答案”:您的主要问题是Rhinomock不会模拟类的成员,而是创建模拟类,然后我们可以为其成员(即属性和函数)设置期望和固定响应。如果您试图测试mock/stub类的成员函数,那么您将面临测试mock框架而非实现的风险

对于逻辑路径依赖于本地(通常是私有)函数的返回值的特定场景,您确实需要一个外部依赖项(另一个对象),它将影响您从该本地函数所需的返回值。对于上面的代码片段,我将编写如下测试:

[Test]
public void TestHasSomething()
{
    // here I am assuming that _thing is being injected in via the constructor
    // you could also do it via a property setter or a function
    var sut = new Something(new object()); 
    Assert.IsTrue(sut.HasSomething);
}
i、 e.无需模拟


这是我过去常常对嘲弄产生的误解之一;我们模拟被测系统(SUT)的依赖关系的行为。类似于:SUT调用了几个依赖性方法,模拟过程提供了固定的响应(而不是去数据库等)来指导逻辑的流动方式

下面是一个简单的示例(注意,我在这个测试中使用了RhinoMocks AAA语法。顺便说一句,我注意到您在代码示例中使用的语法使用了Record Replay范例,只是它没有使用Record and Replay!这可能也会导致问题):

公共类SUT
{
依赖性
公共SUT(依赖关系)
{
_依赖=依赖;
}
...
public int MethodUnderTest()
{
如果(_depend.IsReady)
返回1;
其他的
返回-1;
}
}
...
[测试]
公共void TestSUT_MethodUnderTest()方法
{
var dependency=MockRepository.GenerateMock();
dependency.Stub(d=>d.IsReady).Return(true);
var sut=新sut(依赖项);
Assert.AreEqual(1,sut.MethodUnderTest());
}

所以你的问题是,你试图测试一个模拟对象的行为。这意味着你根本没有在测试你的类

在这种情况下,test double应该是类某物的派生版本。然后重写HasSomething(object)方法并确保HasSomething()调用您的方法

如果我理解正确,您实际上对测试方法HasDynamicFlow(上面的示例中没有描述)感兴趣,而不关心HasSomething的算法

Preet是正确的,因为您可以简单地对某个对象进行子类化,并覆盖HasSomething的行为以使算法短路,但这需要创建一些额外的测试伪代码,Rhino可以有效地消除这些代码

考虑使用动态模拟而不是动态模拟。存根没有那么严格,非常适合处理属性。然而,这些方法需要一些额外的努力

    [Test]
    public void CanStubMethod()
    {
        Foo foo = MockRepository.GenerateStub<Foo>();

        foo.Expect(f => f.HasDynamicFlow()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
        foo.Expect(f => f.HasSomething()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
        foo.Expect(f => f.HasSomething(null)).IgnoreArguments().Return(true);

        Assert.IsTrue(foo.HasDynamicFlow());
    }
[测试]
公共方法()
{
Foo-Foo=MockRepository.GenerateStub();
Expect(f=>f.HasDynamicFlow()).CallOriginalMethod(OriginalCallOptions.noexpection);
foo.Expect(f=>f.HasSomething()).CallOriginalMethod(OriginalCallOptions.noexpection);
Expect(f=>f.HasSomething(null)).IgnoreArguments().Return(true);
Assert.IsTrue(foo.HasDynamicFlow());
}

编辑:添加代码示例并将部分模拟切换为存根

如jpoh所说,模拟对象应传递到SUT中。某物,某物(mockedObject);
    [Test]
    public void CanStubMethod()
    {
        Foo foo = MockRepository.GenerateStub<Foo>();

        foo.Expect(f => f.HasDynamicFlow()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
        foo.Expect(f => f.HasSomething()).CallOriginalMethod(OriginalCallOptions.NoExpectation);
        foo.Expect(f => f.HasSomething(null)).IgnoreArguments().Return(true);

        Assert.IsTrue(foo.HasDynamicFlow());
    }