我正在使用Rhino Mocks 3.6。我见过很多类型的编码。有时使用静态GenerateMock
方法,有时使用new MockRepository()
。我不太了解发生了什么或什么更好。也许某些方法已经过时,但无论如何,让我们回到真正的问题。
我想更好地了解下面的代码中发生了什么,以及更好的测试需要什么。
[TestMethod]
public void TestingProperty()
{
Person repository = MockRepository.GenerateMock<Person>();
// tell rhino.mocks when FirstName is called in the next time, it should return "Monica"
repository.Expect(x => x.Title).Return("Monica");
// get the mocking ready
repository.Replay();
repository.VerifyAllExpectations();
// when getting repository.Title value, we should receive "Monica" defined previously in expectation
Assert.AreEqual(repository.Title, "Monica");
}
我注意到当我删除repository.Replay()
时,一切都在继续工作。重播的目的是什么,是否需要?
还需要VerifyAllExpectations吗?它在内部做什么?
我可以避免手动输入“Monica”并为Person设置一个真实的模拟对象吗?
如果这是一个错误的代码,请告诉我你的建议!
答案 0 :(得分:5)
听起来你没有使用过更新的模拟对象框架。
在较旧的“模拟对象”中,您必须手动对模拟对象的状态进行断言。例如,您将运行测试下的代码,该代码将项添加到模拟对象的列表中。在测试结束时,您将验证是否正确填充了该模拟对象上的列表。这是验证模拟的状态。
这种较旧的风格就像是Rhino存根的不太复杂的版本。
使用较新的模拟对象框架,您将停止验证模拟对象的状态,并开始验证行为。您可以断言您的测试代码如何调用模拟对象,而不是如何设置属性/成员。
您仍然会对正在测试的代码进行经典断言。但是你不会对你的模拟做经典断言。您将设置期望,并使用Rhino断言验证它们。
更正此代码的一些提示:
VerifyAllExepectations
之前调用您的代码,并根据需要将模拟传递给它virtual
或abstract
,或者您的模拟基于interface
以下是一些更正的示例代码:
public class ObjectThatUsesPerson
{
public ObjectThatUsesPerson(Person person)
{
this.person = person;
}
public string SomeMethod()
{
return person.Title;
}
private Person person;
}
[TestMethod]
public void TestingPropertyGotCalled()
{
// Arrange
var mockPerson = MockRepository.GenerateMock<Person>();
mockPerson.Expect(x => x.Title).Return("Monica");
var someObject = new ObjectThatUsesPerson(mockPerson);
// Act
someObject.SomeMethod(); // This internally calls Person.Title
// Assert
repository.VerifyAllExpectations();
// or: mockPerson.AssertWasCalled(x => x.Title);
}
[TestMethod]
public void TestingMethodResult()
{
// Arrange
var stubPerson = MockRepository.GenerateStub<Person>();
stubPerson.Stub(x => x.Title).Return("Monica");
var someObject = new ObjectThatUsesPerson(stubPerson);
// Act
string result = someObject.SomeMethod();
// Assert
Assert.AreEqual("Monica", result, "Expected SomeMethod to return correct value");
}
要测试这是否正常,请尝试这些(在每个之后更改代码):
Expect
行,运行它,并确保它仍然通过(这不是严格的模拟)Expect
行,返回不同的值。运行它,确保它失败SomeMethod
电话。运行它,并确保它通过(不是严格的模拟)SomeMethod
中的代码。运行它,确保它失败答案 1 :(得分:2)
使用RhinoMocks编写测试有两种常用方法 - 具有期望的模拟对象和安排,行为,断言(AAA)。您应该阅读非常详细的http://ayende.com/Wiki/Rhino+Mocks+3.5.ashx文章。
Merlyn Morgan-Graham的回答涵盖了第一种方法。 Follwing是如何使用AAA模型编写相同的测试:
[TestMethod]
public void TestingPropertyUsingAAA()
{
// Arrange
var mockPerson = MockRepository.GenerateStub<Person>();
repository.Stub(x => x.Title).Return("Monica");
// Act
var someObject = new ObjectThatUsesPerson(mockPerson);
someObject.SomeMethod(); // This internally calls Person.Title
// Assert
repository.AssertWasCalled(x => x.Title);
}