I use Rhino Mocks, and I encourage you to do the same. When unit testing, sometimes its necessary to interrogate an object that was passed to a dependency.
Consider the following test code:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1: [Test]
2: public void ShouldSaveObjectWithAllInformation()
3: {
4: string firstName = "Jeffrey";
5: string lastName = "Palermo";
6:
7: MockRepository mocks = new MockRepository();
8: IPersonRepository personRepository = (IPersonRepository) mocks.CreateMock(typeof (IPersonRepository));
9:
10: personRepository.SavePerson(null);
11: GenericConstraint personConstraint = new GenericConstraint();
12: LastCall.On(personRepository).Constraints(personConstraint);
13:
14: mocks.ReplayAll();
15:
16: PersonController controller = new PersonController(personRepository);
17: controller.PersonFirstName = "Jeffrey";
18: controller.PersonLastName = "Palermo";
19: controller.Save();
20:
21: mocks.VerifyAll();
22:
23: Person person = (Person) personConstraint.GetParameterObject();
24: Assert.That(person.FirstName, Is.EqualTo(firstName));
25: Assert.That(person.LastName, Is.EqualTo(lastName));
26: }
This is a case where we have a class that takes information, creates an object and sends it to a dependency. The dependency doesn’t need to return what was just passed to it, but in our unit test, we need to be able to assert that the object was created correctly before being passed to the dependency. This is not an edge case. I run into this scenario quite often.
What did I do to keep my test readable? I created a Rhino Mocks constraint class that captures the argument passed to a dependency. Later, I can write plain old asserts that verify the state of the object. Here is the class:
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
1: public class GenericConstraint : AbstractConstraint
2: {
3: object _theObject;
4:
5: public override bool Eval(object obj)
6: {
7: _theObject = obj;
8: return true;
9: }
10:
11: public object GetParameterObject()
12: {
13: return _theObject;
14: }
15:
16: public override string Message
17: {
18: get { return ""; }
19: }
20: }
I prefer this over even the built-in constraints Rhino Mocks provides because I find the Assert syntax to be more familiar with more programmers than the in-line constraint syntax. Notice on line 12 of the test listing that I’m assigning this constraint to the mocked call to IPersonRepository. This allows me to come back later on line 23 and pull the object for interrogation. Once I have a reference to the object that was passed to my dependency, I can write the appropriate asserts.
Feel free to use this constraint class or comment with how you’ve handled this situation.
I know the .Do() method will work, but I’ve found that sometimes it’s a bit more verbose and less obvious than the GenericConstraints way of doing it. So I’ve added a genericised version of the class:
public class Constraint : AbstractConstraint where T : class
{
T _theObject;
public override bool Eval(object obj)
{
_theObject = obj as T;
return _theObject != null;
}
public T GetParameterObject()
{
return _theObject;
}
public override string Message
{
get { return “”; }
}
}
Which works well and saves that fugly cast.
Thank you!!
Another reason for Rhino Mocks Generic Constraint…
http://aaronfeng.com/articles/2007/10/08/another-reason-for-rhino-mocks-generic-constraint
@Robert:
Regarding Equals or constraints you wrote
“@Martin: I prefer that too but in some cases i have a property on my object that is meant to be set to an autonumber or the current date (something out of my control), so i want to ignore that property *for just this test*
”
In cases like this I would factor out the magic into an “IMagicProvider” – for example, a class that can provide the current time. This way you have control over your environment in the test – just use, say, a mock or a stub that provides a fixed timestamp, and you will be able to use Equals.
I prefer this static approach to having to deal with dynamic magic in my tests.
And that is why commenting about stuff and using a text editor to scrap up code after 2 am is a bad idea (Predicate should be Predicate
)
sorry folks
sorry hit post button just before i finished off,
)
(if my post can be fixed much appreciated
the c# example should read:
string firstName = “Jeffrey”;
string lastName = “Palermo”;
Predicate constraint = new Predicate(delegate(Person p)
{
return p.FirstName == firstName && p.LastName == lastName ;
});
MockRepository mocks = new MockRepository();
IPersonRepository personRepository = mocks.CreateMock();
personRepository.SavePerson(null);(constraint));
LastCall.On(personRepository).Constraints(Is.Matching
mocks.ReplayAll();
PersonController controller = new PersonController(personRepository);
controller.PersonFirstName = firstName;
controller.PersonLastName = lastName;
controller.Save();
mocks.VerifyAll();
Lol, me too, been playing with a similar idea recently
I also tend to use the Equals(obj) method, however sometimes (such as in my newest project using Boo) I’ve tended to also use a different technique that can be done in c# 2, but really doesn’t look really nearly as clean compared to Boo’s closures (or the new lambda expressions in c# 3).
This way also allows you to just optionally test certain values of the expected object passed which handles Robert’s autonumber issue.
(upgraded to generics – but not the record/playback layout)
________________________________________________
using Rhino.Mocks;
using Rhino.Mocks.Constraints;
string firstName = “Jeffrey”;
string lastName = “Palermo”;
Predicate constraint = new Predicate(delegate(Person p)
{
return p.FirstName == firstName && p.LastName == lastName ;
});
MockRepository mocks = new MockRepository();
IPersonRepository personRepository = mocks.CreateMock();
personRepository.SavePerson(null);
GenericConstraint personConstraint = new GenericConstraint();
LastCall.On(personRepository).Constraints(Is.Matching(constraint));
mocks.ReplayAll();
PersonController controller = new PersonController(personRepository);
controller.PersonFirstName = firstName;
controller.PersonLastName = lastName;
controller.Save();
mocks.VerifyAll();
_____________________________________
Haven’t really gotten into blogging yet (not like I’ve tried hard … got like 15 drafts and one published rant), but was wierdly enough already writing a post on this technique a day or two ago before I saw this, which including some ways that I’ve used to handle the multiple calls Robert is mentioning.
I’m gonna still blog a bit about this technique (this one I’m am actually gonna publish!) and “extensions” to it I’ve used such as currying ala:
(note it’s in boo I’ll post c# version as well)
[Test]
def sometest():
invalidReason = “my reason”
constraint = def(player as Player) as Predicate[of InvalidMoveEventArgs]:
return {e as InvalidMoveEventArgs | e.Player == player & e.Reason = invalidReason}
/……./
This technique is ideally suited to ordered, but the regular straight closure route could be used in unordered (by keeping some state as to which one of the expected values has/hasn’t been passed yet in the enclosing method/data holder…)
You stole my idea!
Now maybe you can steal an idea off me that i haven’t thought of yet:
What happens when your test expects that SavePerson be called twice, with completely different parameters? Rhino can handle this (ordered or unordered) for cases where the pbject properties are “unrolled” into the method args, but if you want to test data objects, you’re in trouble (or should i say, i’m in trouble)
What I ended up doing is creating another contstraint that stores EACH argument into a list, and then checking the contents of that list. But that seems very far from the original intent of rhino
What do you think?
@Martin: I prefer that too but in some cases i have a property on my object that is meant to be set to an autonumber or the current date (something out of my control), so i want to ignore that property *for just this test*
@Martin,
I, too, favor overriding the Equals(obj) method, and encourage that whenever possible (and over the technique described here).
In cases where that won’t work or is insufficient, the above is the best I’m come up with in .Net 1.1
Note, in .Net 2.0 and the latest release of Rhino Mocks, the “Do( )” method can be used with an anonymous delegate to hold the NUnit asserts.
I favour implementing Equals on the parameter object over using the constraints.
This way I get very simple code like
Person expectedPerson = new Person(firstName, lastName);
personRepository.SavePerson(expectedPerson);
LastCall.On(personRepository);
// …
mockRepository.VerifyAll();
The Asserts are that in a way they circumvent the object-orientation by asserting state outside of the object itself – and they make for bulky test-code that needs to change in synch with changes to the Person class.
Using Equals this reduces to a matter of constructing the expected object (standard constructor) and using its built-in Equality method.
@Garry,
Your description is correct.
If the dependency required 3 arguments, then you would create 3 instances of GenericConstraint, and each one would receive a method argument. If the method has 7 arguments, you have to provide 7 GenericConstraint instances, and you can name each one appropriately so it will be easy to retrieve the parameter objects one at a time.
It took me a few reads to get it but (please correct me if I’m wrong):
A constraint is checked by passing the parameters fed to the method to the Eval function as an object. Jeff’s object stores this parameter for later use and returns true (as if the constraint was satisfied). This means we have a copy of what was passed to the method and we use the GetParameterObject function to later retrieve the object so we can test its contents against our expectations.
One question that this has raised for myself is how this works for multi-parameter methods, is the parameter object an array of objects which we need to cast individually? This would make sense to me but I haven’t had chance to try it out.
@Joe
That is the new behavioral constraint assertion model of NUnit 2.4
http://www.lostechies.com/blogs/joe_ocampo/archive/2007/07/22/nunit-s-new-constraint-model.aspx
I don’t get the test. Looks like interesting re-use, and it’s certainly “readable”, but I’m not getting it on first through fifth glance. If you have time at some point, I’d like to dissect it.
Awesome example. This is much easier then doing a Do() to test the parameters.
What test framework uses “Assert.That”?
ps and I hate to ask and seem nit-picky, but do you think you could turn line numbers off when you post code? I understand that it has its aesthetic advantages, but to simpletons like myself who have to cut and paste and try everything out in the IDE to see how it really works, they’re a pain.
@Garry,
Yes, I do use the Generic syntax. I happened to be working in a VS2003 project when I whipped up this sample code.
Very interesting! I’ll be trying this out soon. I agree that the assertions contained in your expectations can be quite hidden at times and this looks like a good way of dragging those out.
As an aside, have you seen the generic syntax for MockRepository.CreateMock? I find it makes my mock object creation look much nicer:
IPersonRepository personRepository = mocks.CreateMock();
Excuse anything lost in the VB to C# translation.