Reputation: 16411
I am using Rhino Mocks 3.6. I have seen many types of coding. Sometimes using static GenerateMock
method, sometimes using new MockRepository()
. I don't understand pretty well what is happening or what is better. Maybe some methods are obsolete, but anyway, let's go to the real issue.
I would like to understand better what is happening in the code below and what is really needed to have a better test.
[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");
}
I noticed when I remove repository.Replay()
, everything keeps on working. What is the purpose of Replay, is it needed?
VerifyAllExpectations is also needed? What is it doing internally?
Can I avoid typing manually "Monica" and have a real mock object for Person?
If this is a bad code please let me know your suggestions!
Upvotes: 0
Views: 1558
Reputation: 59131
It sounds like you haven't worked with more recent mock object frameworks.
In older "mock objects", you have to do assertions manually against state of the mock object. For example, you'd run the code under test, which adds items to a list on your mock object. At the end of your test, you'd verify that the list on that mock object is populated correctly. This is verifying the state of the mock.
This older style is like a less sophisticated version of a Rhino stub.
With newer mock object frameworks, you stop verifying state of mock objects, and start verifying behavior. You make assertions about how your code under test calls your mock objects, not how properties/members are set.
You'll still do your classical assertions on the code under test. But you won't do classical assertions on your mocks. You'll instead set up expectations, and verify them with Rhino assertions.
Some tips to correct this code:
VerifyAllExepectations
, passing mocks to it as necessaryvirtual
or abstract
, or that your mock is based off an interface
Here's some corrected example code:
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");
}
To test that this is working correctly, try these things (change the code back after each one):
Expect
line, run it, and make sure it still passes (this isn't a strict mock)Expect
line, returning a different value. Run it, and make sure it failsSomeMethod
call. Run it, and make sure it passes (not a strict mock)SomeMethod
. Run it, and make sure it failsUpvotes: 5
Reputation: 100545
There are 2 common approaches to writing tests with RhinoMocks - mock objects with expectations and Arrange, Act, Assert (AAA). You should read http://ayende.com/Wiki/Rhino+Mocks+3.5.ashx article that covers it in great detail.
Merlyn Morgan-Graham answer covers first approach. Follwing is how you can write the same test using AAA model:
[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);
}
Upvotes: 2