Introduction
Since the 3rd of October 2008, Ayende has released a new version of Rhino Mocks.
Rhino Mocks is "A dynamic mock object framework for the .Net platform. It's purpose is to ease testing by allowing the developer to create mock implementations of custom objects and verify the interactions using unit testing."
This version now supports the AAA (Arrange, Act and Assert) syntax.
The major feature in Rhino Mocks 3.5 is the AAA syntax.
Arrange, Act, Assert is a classic way to setup your tests. First you
arrange the state, then you execute the code under test, finally you
assert that the expected state change happened.
Which makes it more easy to read and use. I will try to explain how to use it and show the difference between the old and the new syntax using VB.Net. This article is not about why and when you should use Mocks. This is also not an article on best practices. The Repository for example is kept light it is just there to explain things.
I will also write just on test to see if the service returns the correct something if it gets called. For this it needs to use the Repository implementation but because we don't want the test to go to the database I will Mock it out.
You can find me and some other bright people at LessThanDot
Prerequisites
- I used Rhino Mocks 3.5 for this, which can be found here.
- And NUnit 2.4.6.0, which can be found here.
Set up
For this example I will use A Service and a Repository. The Service calls the Repository to do the dirty work. Both also have an interface which is usually the easier way to Mock something.
First we create the IService and IRepository interfaces
Namespace Service
Public Interface IService
Function FindAllProducts() As IList(Of Model.Product)
End Interface
End Namespace
Namespace Repository
Public Interface IRepository(Of T)
Function FindAll() As IList(Of T)
End Interface
End Namespace
Now both Interfaces need an implementation. Nothing fancy, just a simple implementation. The Repository code is there just as an example. It won't even work. And it doesn't need to work because we are going to mock it out.
First the service. This simply calls the repository. It also takes a IRepository(Of Model.Product) as a parameter so that we can inject an implementation in it.
Namespace Service
Public Class Service
Implements IService
Private _Repository As Repository.IRepository(Of Model.Product)
Public Sub New(ByVal Repository As Repository.IRepository(Of Model.Product))
_Repository = Repository
End Sub
Public Function FindAllProducts() As IList(Of Model.Product) _
Implements IService.FindAllProducts
Return _Repository.FindAll
End Function
End Class
End Namespace
And now an implementation of IRepository which we won't use in the tests.
Imports System.Data.SqlClient
Namespace Repository
Public Class ProductRepository
Implements IRepository(Of Model.Product)
Public Function FindAll() As System.Collections.Generic.IList(Of Model.Product) _
Implements IRepository(Of Model.Product).FindAll
Dim _List As New List(Of Model.Product)
Dim _con As New SqlConnection
Dim _com As New SqlCommand
Dim _reader As SqlDataReader
_con.ConnectionString = "some connectionstring"
_con.Open()
_com.CommandText = "Select Name from product"
_com.Connection = _con
_reader = _com.ExecuteReader
While _reader.Read
_List.Add(New Model.Product(_reader.GetString(0)))
End While
Return _List
End Function
End Class
End Namespace</remarks>
The tests
Rhino Mocks 3.4
In the previous version of Rhino Mocks you used Replay and Verify syntax. So our test would look like this.
Imports NUnit.Framework
Imports Rhino.Mocks
Namespace MockedTest34
<testfixture()> _
Public Class TestService
#Region " Private members "
Private _Mocker As MockRepository
#End Region
#Region " Setup and TearDown "
<setup()> _
Public Sub Setup()
_Mocker = New MockRepository
End Sub
<teardown()> _
Public Sub TearDown()
_Mocker.ReplayAll()
_Mocker.VerifyAll()
End Sub
#End Region
#Region " Tests "
<test()> _
Public Sub Test_If_Service_Returns_A_List_Of_Products()
Dim _Repository As Repository.IRepository(Of Model.Product) = _
_Mocker.DynamicMock(Of Repository.IRepository(Of Model.Product))()
Dim _Service As Service.IService = New Service.Service(_Repository)
Rhino.Mocks.Expect.Call(_Repository.FindAll).IgnoreArguments.Return(New List(Of Model.Product))
_Mocker.ReplayAll()
Assert.IsNotNull(_Service.FindAllProducts)
End Sub
#End Region
End Class
End Namespace</test()></teardown()></setup()></testfixture()>
You see here that we an Instance of MockRepository. That MockRepository will make us a Mock using the DynamicMock method. In this case we Mock the Repository. We then make our Service and we pass in our Mocked Repository. After that we set our Expectation. We expect that the Findall method will be called on the Repository. We now have to call The ReplayAll method on the MockRepository object. Lastly we assert if the service returns something, we don't really care what that may be but since our function must return an Ilist(Of Model.Product) we don't really have to check that.
Rhino Mocks 3.5
In the new version the old code still works ;-). But we can (and should) use the newer AAA syntax instead. As you will see in the code example it is a bit simpler to use.
Imports Nunit.FrameWork
Imports Rhino.Mocks
Namespace MockedTest35
<testfixture()> _
Public Class TestService
#Region " Tests "
<test()> _
Public Sub Test_If_Service_Returns_A_List_Of_Products()
Dim _Repository As Repository.IRepository(Of Model.Product) = _
MockRepository.GenerateMock(Of Repository.IRepository(Of Model.Product))()
Dim _Service As Service.IService = New Service.Service(_Repository)
_Repository.Stub(Function(e) e.FindAll).IgnoreArguments.Return(New List(Of Model.Product))
Assert.IsNotNull(_Service.FindAllProducts)
End Sub
#End Region
End Class
End Namespace</test()></remarks></testfixture()></remarks>
First we see that we no longer have to make and instance of MockRepository. We will use the Static/Shared methods of MockRepository instead. To make the mock we use the GenerateMock method of the MockRepository. Then we pass that mocked object to a new Service. We set our expectations via an extension method called stub. it uses a lambda expression to decide which method will be called. We set the desired return value and we use IgnoreArguments although not really needed in this instance because findall has no arguments. After that we call the service method and see if it returns something.
As you can see the new method no longer needs the ReplayAll and VerifyAll syntax either.
I hope this explains the difference well enough for you to go out and use this wonderfull product.
Points of Interest
If you switch from Rhino Mocks 3.4 to Rhino Mocks 3.5 the compiler will complain that Expect has no such method on the lines where you have Expect.Call. This is easily solved by adding Rhino.Mocks. In front of it. this is caused by the fact that Ayende also added an Extension method with the same name and the compiler can't make the difference. Adding an imports doesn't help.
History
10/07/2008 First version
10/07/2008 Added a link to an AAA explanation article. And corrected some typos.