Using Rhino.Mocks 3.5-and-up with VB.NET 9

Choosing a Mocking Framework

Lately I have been getting a bit more serious about Unit Testing, dipping my toe in the Test-Driven Development pool. In reading up on the subject, I came across the concept of using mocking frameworks to dynamically and automatically create stub- and mock- objects. i began looking into the various frameworks available, with an eye to open-source and free-as-in-beer frameworks, as i was not yet sure if i was going to hold my nose and jump all the way into the water, or keep splashing about in the kiddie end of the pool, and saw no sense in spending money on a framework i might not use.

I had been reading a lot of good things about Ayende’s Rhino.Mocks Framework in CoDe Magazine; then recently I added testing guru Roy Osherove’s book The Art of Unit Testing to my O’Reilly Safari books online Bookshelf. Roy uses Rhino.Mocks, henceforth referred to simply as Rhino, almost exclusively as the mocking framework for his examples in the book.

Rhino works just fine with Microsoft’s testing framework MSTest, as well as NUnit. I have not tried it with other frameworks, but I’m sure it works equally well with all, as it is supplied in the form of a .DLL, to which you simply add a reference in your testing project. The current version as of this writing was 3.6, which I downloaded from the Rhino.Mocks download page.

 

Rhino 3.5+ works with C# and…VB.Net… or does it?

I should mention at this point that all the code to follow uses Rhino’s new-as-of-version-3.5 AAA syntax- that is, Arrange, Act, Assert, which you should Google if you’re not familiar with it, as it is a primary underpinning to the modern TDD approach. I should also mention that this syntax isn’t usable from VB.Net 8, a.k.a. VB.Net 2005. It requires capabilities not added to the language until the 2008 version.

If you look through the Rhino documentation— which is all in C# — for the new syntax, you may wonder if you can use it from VB.Net at all! When you see a line like this in the C# docs:

RegistryObj.Stub(R => R.GetValue(param1, param2, param3)).Return(param3);

You may be forgiven for wondering, “what the heck is that?” “That” is C# syntax for lambda expressions. I won’t go into detail as to what they are— you can look them up on MSDN for the details.

The important part is to understand what’s going on: we have a stub of a Registry wrapper object I wrote to test code that calls the Registry without having to actually touch the real Registry. We have a Rhino-generated stub of a function, which we are setting up to return a specific value when called with specific parameters. And finally, we have a C# lambda expression.

So how does one read that lambda syntax, and what does it mean? According to Microsoft it is read as “R goes to R [etc.]”. As far as this particular usage, it essentially is a way of defining a function in-line, without having to code up an actual function elsewhere.

 

Lambdas in VB.Net; setting up a stubbed function to return a value

So, you are no doubt asking, “can one do this in VB.Net?” The answer, of course, is “yes you can!” This is what the above call would look like in VB.Net, using VB’s version of the lambda syntax:

RegistryObj.Stub(Function(R) R.GetValue(param1, param2, param3).Return(param3))

You can also specify the type of R, which can help VB.Net deal with some of the weirder Rhino syntax, like this:

RegistryObj.Stub(Function(R as IRegistryWrap) R.GetValue(param1, param2, param3).Return(param3))

And that’s that! Lambdas in VB.Net, sorted! Right? Er, right? No? You mean, you want to be able to use other parts of Rhino? Parts that require even stickier syntax? Demanding, aren’t we?

 

Calling Rhino’s .AssertWasCalled from VB.Net with a sub

It turns out that there is a really handy extension method that Rhino provides, .AssertWasCalled(), that we would like to be able to call from VB.Net. Calling this method using a lambda and a function works just like the examples above, in both C# and VB.Net. However– there is a “gotcha” when the method you’re calling in the lambda expression is a sub-routine, or, in C#-speak, a “void function”. The problem is that VB.Net does not support lambda expressions without a return value, as detailed by Paul Kimmel on Developer.com.

So, how can we make the call in VB.Net? This will serve as a good example for another difficult-to-call-from-VB.Net method of Rhino. Let’s look at how to call this from C#, as per the documentation:

ClipboardWrapper.AssertWasCalled(C => C.SetFileDropList(fred));

What have we here? This is simply a stubbed version of another one of my wrapper methods, this time wrapping the Clipboard object; we’re calling Rhino’s .AssertWasCalled extension method on it, using a lambda expression, and then setting the void method we need to test as to whether it was called. Very similar to the above code.

So, how do we make the call in VB.Net? The following code would work just fine if .SetFileDropList was a VB function:

ClipboardWrapper.AssertWasCalled(Function (C) C.SetFileDropList(fred))

 

But, since .SetFileDropList is actually a sub-routine, what we actually get is this error: 

ExpDoesNotProduceValue2

If you refer to Paul Kimmel’s article, linked a few lines up, you’ll see that this is the exact error he mentions.

To fix this, we need to use his instructions and create a delegate function. That is, because we can’t create an inline delegate until the next version of VB.Net (2010), we need to actually add a separate wrapper function that returns Nothing, reference it inside the .AssertWasCalled call, and that will satisfy both the compiler and Rhino.Mocks.

Something like this:

<TestMethod()> _
Public Sub MyTest()
' [...]
  MyClipboardWrapper.AssertWasCalled(Function(C) WrapperFunction(C))
End Sub
 
Function WrapperFunction(ByRef ClipObj As IClipboard) As Object
        ClipObj.SetFileDropList(fred)
        Return (Nothing)
End Function

 

Why yes, it is a bit ugly; but at least it allows you to keep your tests in VB.Net! And that’s what I promised at the start of this article.

Also, note that I used the type of the Interface in the wrapper function, rather than just declaring it as object, which Kimmel claims will work. I found that the compiler complained about late binding with Option Strict on the ClipObj.SetFileDropList(fred) line unless I declared ClipObj as its interface type, IClipboard.

 

And that’s it for this article; I will likely have more on using Rhino.Mocks with VB.Net in the near future.

Advertisements
  1. #1 by Ben Hiron-Grimes on April 19, 2015 - 5:47 pm

    Hi, yes a follow up would be great.. there’s precious little out there for beginners in using rhino mocks with VB.net…

  2. #2 by andrewcushen on January 24, 2012 - 9:30 pm

    Yes, Jeff, one of these days I should add a follow-up post. This post was specific to VB.NET 9.0/VS 2008.

    VB.NET 10.0 in VS2010 has much fuller support for lambdas, allowing both Functions that directly return values, as well as Subs that do not.The above workaround is no longer needed.

  3. #3 by Jeff on January 24, 2012 - 1:59 pm

    Now that VS2010 is out, there seems to be a more succinct way to call .AssertWasCalled:

    MyClipboardWrapper.AssertWasCalled(Sub(c) c.WrapperFunction(ExpectedParm))

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: