About the author

Steven Harmansteven harman :: makes sweet software with computers!

For recent posts and more about me, scroll to the bottom.

Subscribe

  • Subscribe to my feed. via RSS
  • Subscribe via email via email

News

Badges

  • Subtext Project
  • Support Subtext

Expectation Based Testing with Mocks

Last week I talked about Rubifying your C# code by adding the .Each() extension method to the IEnumerable<T> interface. I was discussing that code with one of the guys at work and he asked a brilliant question

So, how did you test that?

I was floored. Being such a test-first fan boy I couldn’t believe that I had failed to write that little extension method in a TDD manner. Hell, I hadn’t even done TAD!

So how do I test it?

There are no doubt a plethora of ways to test this small bit of code - some right and many wrong. In the end I turned to my good friend Rhino.Mocks to do some expectation, or interaction, based testing.

If you don’t fully grok mocks, and in particular Rhino.Mocks, the following code might look a little foreign. I’ll try to explain the basics of what’s going on in the below code snippet, but be warned I’ll be doing a little bit of hand-waving to make the code more soluble. I’ll be doing a much deeper dive in some future posts, so stay tuned!

   1: public class When_Executing_Each_On_IEnumerable_That_Has_Items : SpecBase
   2: {
   3:     [Test]
   4:     public void Should_Executes_CodeBlock_On_Every_Item()
   5:     {
   6:         ITestWidget myWidget = CreateMock<ITestWidget>();
   7:         IEnumerable<ITestWidget> widgets = 
   8:             new ITestWidget[] { myWidget, myWidget, myWidget, myWidget, myWidget };
   9:  
  10:         using (Record)
  11:         {
  12:             Expect.Call(myWidget.Foo()).Return("I was called!").Repeat.Times(5);
  13:         }
  14:  
  15:         using (Playback)
  16:         {
  17:             widgets.Each(w =>
  18:                 {
  19:                     string output = w.Foo();
  20:                     Console.WriteLine(output);
  21:                 });
  22:         }
  23:     }
  24: }
  25:  
  26: public interface ITestWidget
  27: {
  28:     string Foo();
  29: }

All of the above hand-waving is really just adding some syntactic sugar around use of the Rhino.Mocks MockRepository class, and its all done in the SpecBase class which you can get via the link at the end of this post.

So, what am I expecting?

In lines 6-8 I created a mock of the ITestWidget interface and then built an array that contained that object. Well, really it contains 5 references to that one object. With the array built, I flipped the MockRepository into Record mode so I could tell Rhino.Mocks what I was expecting to happen to my mock object.

   10: using (Record)
   11: {
   12:     Expect.Call(myWidget.Foo()).Return("I was called!").Repeat.Times(5);
   13: }

I told Rhino.Mocks to Expect a Call to the myWidget object’s Foo method. And when that method is called I want the mock to Return the string "I was called!". Oh, and I also expect that method to be called, or Repeated, five (5) Times.

And what is happening?

Once all of my expectations are setup I switch the MockRepository to Playback mode, meaning I’m ready to exercise the expectations I setup during Record mode.

   15: using (Playback)
   16: {
   17:     widgets.Each(w =>
   18:         {
   19:             string output = w.Foo();
   20:             Console.WriteLine(output);
   21:         });
   22: }

Once in playback mode I simply need to exercise the SUT... or in this case the one particular method I’m concerned with. Into that method I’m passing a Lambda expression with a code block that will actually execute the method I’ve set the expectation on.

What happens when I run the test?

I get some output, naturally!

Seriously though, if I were doing this test-first, as I should have, the test would have failed because I’d not yet written the code to implement the Each method.

But after adding just the code needed to get the test to pass, and then running the test, I should see all green. Oh, and the console output looks something like

   1: I was called!
   2: I was called!
   3: I was called!
   4: I was called!
   5: I was called!

Nice! The string I expected to be returned from the method was written out to the console the exact number of times I expected.

Meaning?

Meaning the method behaved just as I expected it to. My test... or my Spec in BDD parlance, specified how the method should behave and then verified that it behaved as specified.

See what I did there? BDD isn’t sooo scary, right?*

Get the code

You can get the complete source code in one of two ways

  1. The code as it existed at the time I wrote this post.
  2. The living code, including any changes and complete version history, from the CodeIncubator project’s Subversion repository.

I’d recommend pulling down the live code directly out of the SVN repository to be sure to get the latest and greatest bits. We, or at least I, plan to keep adding bits and use the project to stretch my BDD legs.

*Note: I’ve only recently started dipping my toes in the BDD waters, but so far I’m really liking what I’m seeing!

Technorati Tags: , , , , , ,

What others are saying.

# re: Expectation Based Testing with Mocks
Gravatar tim
Jan 27, 2008
OK, followed the bouncing ball pretty well, but gotta ask: I see practically no difference between TDD and BDD here...other than you saying spec v. test. Granted, this isn't that deep, so maybe there's really nothing to notice on this one post, but I'm having trouble seeing a difference between the two at this point.
# re: Expectation Based Testing with Mocks
Gravatar Steven Harman
Jan 27, 2008
@Tim, I've only recently started exploring BDD, but I would say that's pretty accurate.

I see BDD as the natural evolution of TDD rather than an all new thing. Much of the difference is in the language (Spec rather than Test, Should rather than Assert, etc...), but I also think of it as a tweak in perspective. With BDD I'm trying to think about my code at a higher level and write my specs so they are ignorant of any implementation details of the SUT.

As luck would have it, I just stumbled across a post that describes BDD vs. TDD... maybe you'll find it useful too.
# Expectation Based Testing with Mocks
Gravatar DotNetKicks.com
Jan 27, 2008
You've been kicked (a good thing) - Trackback from DotNetKicks.com
# Link Listing - January 27, 2008
Gravatar Christopher Steen
Jan 28, 2008
MSBuild MSBuildContrib January Release [Via: Scott Dorman ] Sharepoint SharePoint Lists as DataTables...
# Link Listing - January 27, 2008
Gravatar Christopher Steen
Jan 28, 2008
Link Listing - January 27, 2008
# re: Expectation Based Testing with Mocks
Gravatar Jim Holmes
Jan 28, 2008
Feh. This whole TDD thing is highly overrated anyway.

(That would be irony to those of you who don't know me...)
# re: Expectation Based Testing with Mocks
Gravatar Oran
Jan 29, 2008
The way you've focused on the output from Console.WriteLine might lead the reader to believe that this kind of manual verification is how you know the test has passed, when in reality there is an implicit VerifyAll() at the end of the using(Playback) block that programmatically verifies the expecation that Foo() was called exactly 5 times. But unless you know about this "declarative magic", the self-verifying aspect of this test is non-obvious.
# re: Expectation Based Testing with Mocks
Gravatar Steven Harman
Jan 29, 2008
@Oran,
Very good point! I've been using Rhino.Mocks for such a long time that the implicit VerifyAll is... well implicitly-obvious to me.

At any rate, Oran is right kids - you most certainly do not want to manually verify your tests... let your testing and mock frameworks do as much of the work for you as they can.
# re: Expectation Based Testing with Mocks
Gravatar Marlun
Jan 31, 2008
Nice post and I have to thank you for using the <abbr> tag when using abbreviations I've complained in silence when reading a lot of blog posts where I have no idea what the abbreviations mean.
# 15 Minutes with Rhino.Mocks
Gravatar StevenHarman.net
Feb 19, 2008
15 Minutes with Rhino.Mocks
Comments have been closed on this topic.