这是我的情况: 我想测试“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)”就是不能以这种方式嘲笑。它并没有像我期待的那样让我'真实'。
感谢。
答案 0 :(得分:2)
回应OP的'回答':你的主要问题是RhinoMocks不会模拟类的成员 - 而是创建模拟类,然后我们可以为其成员设置期望和预制响应(即属性和功能)。如果您尝试测试模拟/存根类的成员函数,则存在测试模拟框架而非实现的风险。
对于逻辑路径依赖于本地(通常是私有)函数的返回值的特定场景,您确实需要一个外部依赖项(另一个对象),它将影响您从该本地函数所需的返回值。对于上面的代码片段,我会按如下方式编写测试:
[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);
}
即。不需要嘲笑。
这是我过去常常在嘲笑方面的一个误解点;我们模拟被测系统(SUT)的依赖行为。类似的东西:SUT调用依赖的几个方法,而模拟过程提供预设的响应(而不是去数据库等)来指导逻辑流的方式。
一个简单的例子是如下(请注意,我已经使用RhinoMocks AAA语法进行此测试。顺便说一句,我注意到您使用您的代码示例中的语法使用记录 - 重放模式,不同之处在于它没有使用Record和Replay!这可能会导致问题):
public class SUT
{
Dependency _depend
public SUT (Dependency depend)
{
_depend = depend;
}
...
public int MethodUnderTest()
{
if (_depend.IsReady)
return 1;
else
return -1;
}
}
...
[Test]
public void TestSUT_MethodUnderTest()
{
var dependency = MockRepository.GenerateMock<Dependency>();
dependency.Stub(d => d.IsReady).Return(true);
var sut = new SUT(dependency);
Assert.AreEqual(1, sut.MethodUnderTest());
}
所以你遇到的问题是你试图测试一个模拟对象的行为。这意味着你根本没有真正测试你的课程!
答案 1 :(得分:0)
在这种情况下,你的test double应该是Something类的派生版本。然后重写方法HasSomething(object)并确保HasSomething()调用您的方法。
答案 2 :(得分:0)
如果我理解正确,你实际上对测试方法HasDynamicFlow感兴趣(在上面的例子中没有描述),而不考虑你自己的HasSomething算法。
Preet是正确的,你可以简单地继承Something并覆盖HasSomething的行为以使算法短路,但这需要创建一些额外的测试虚拟代码,Rhino可以有效地消除这些代码。
考虑使用 Partial Mock Stub而不是动态模拟。存根不太严格,非常适合使用Properties。然而,方法需要一些额外的努力。
[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());
}
编辑:添加了代码示例并将Partial Mock切换为Stub