Unit Testing with Rhino Mock .Net


I am covering unit testing with mock objects using Rhino mock .net library.

What is unit Test?

It is a method of testing a smallest unit of source code. Unit can be function or method. Unit tests are created during development process by developers or occasionally white box testers. Ideally each test case should be independent from each others. Unit tests helps to maintain quality of your application, it helps to find out any error or discrepancy during development process. There are many libraries available to unit test source code like nunit, mbunit, junit, MSTest etc.

What is mock object?

  • The mock objects are proxy of real objects which mimic behavior of real objects. Mock objects are mainly used in testing when testing with real objects is impractical or impossible to incorporate in unit testing. Below is some characteristics that can help you to decide to use mock objects.
    • Testing data is dynamic i.e. testing results cannot be determine on every test.
    • Unit testing includes network or database dependencies.
    • You don’t know about behavior of dependent objects.
  • Mock objects in this sense do a little more: their method implementations contain assertions of their own. This means that a true mock, in this sense, will examine the context of each call— perhaps checking the order in which its methods are called, perhaps performing tests on the data passed into the method calls as arguments.

What is Rhino Mock?

It is a dynamic mock object framework for the .Net platform. It includes features from EasyMock.Net and NMock. Below is some features of this library:

  • It can mock interfaces, delegates and classes including parameterized constructors.
  • Explicit Record & replay model for expectations.
  • Can work for strong type mock objects.
  • Expectations are based on
  • Argument matching.
  • Constraints matching.
  • Custom callback to verify the expected arguments using your own code.
  • Setting actions of methods, properties to return pre determine value.
  • you can also tests methods which doesn’t return any value. In this case you can test interaction based testing ie. you can verify specific sequence of actions and then you can verify these actions according to predefined order.
  • State base Testing: initiate action and then check  expected results.

Rules for using Rhino Mock

  • Rhino mock can only mock interfaces, delegates and virtual methods.
  • Mock objects cannot be created from sealed class.
  • Mock Objects cannot be create from private interface.

Examples of Rhino Mock

Expect Call

To create any mock object you need to create instance of MockRepository Class which act as project presenter.

I am taking very simple example how to create mock object and set expectation on property.

[TestMethod] 

public void TestMethod2() 
{ 
	//Testing with Mock Object 
    MockRepository repo = new MockRepository(); 
    TestClassForMockTesting obj = repo.CreateMock(); 
    Expect.Call(obj.Message).Return("hello"); 
    repo.ReplayAll();
    Assert.AreEqual("hello", obj.Message); 
    repo.VerifyAll(); 
}
public class TestClassForMockTesting
{
    public TestClassForMockTesting() { }
    public string Message
    {
        get
        {
            return Guid.NewGuid().ToString();
        }
    }
}

Output

Above code will raise exception : "Invalid call, the last call has been used or no call has been made (make sure that you are calling a virtual (C#) / Overridable (VB) method)." because any expect call can only set values for Virtual methods or properties. If you make Messageproperty as virtual then mock framework will set Message value as “Hello” instead on GUID which can’t be predicated on every call. if you do same test with real object it will always because you can’t return values.So if we make Message property as Virtual this test will pass.

public virtual string Message { get { return Guid.NewGuid().ToString(); } } 

Expect call for DbConnection and void method

this example test dbconnection open method. First we create mock dbconnection and inject dbconnection object through constructor as we know that without database connection string real database connection object will raise exception on calling Open method.On thing note here to expect call void method we have to use anonymous delegate in Expect.Call method.

[TestMethod]
public void TestDbConnection()
{
	//Testing with Mock Object
	MockRepository repo = new MockRepository();
	IDbConnection mockConn = repo.CreateMock();
	TestClassForMockTesting obj = repo.CreateMock(mockConn);
	//Expecting void methods
	Expect.Call(delegate { mockConn.Open(); });
	repo.ReplayAll();
	Assert.IsTrue(obj.openConnection());
	repo.VerifyAll();
}
public class TestClassForMockTesting
{
    public TestClassForMockTesting()
    {
    }
    //constructor for injecting Mock DbConnection
    public TestClassForMockTesting(IDbConnection conn)
    {
        _conn = conn;
    }
    IDbConnection _conn;
    public virtual string Message { get { return Guid.NewGuid().ToString(); } }
    public bool openConnection()
    {
        try
        {
            _conn.Open();
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }
    }
}

If you don’t call this statement Expect.Call(delegate { mockConn.Open(); }) test will fail and will give error like

image

Test DataAccess Layer’s Method

This example shows how can we mock database connection and test our unit test. Expect.Call(obj.GetHotel(2)).Return(h).Repeat.Twice() this line tells same expectation twice because obj.GetHotel(2) statement is using two times.

public void TestGetHotels()
{
	 //Testing with Mock Object
	 MockRepository repo = new MockRepository();
	 IDbConnection mockConn = repo.CreateMock();
	 ITestClassForMockTesting obj = repo.CreateMock();
	 obj.DBConn = mockConn;
	 //Expecting void methods
	 Hotel h = new Hotel();
	 h.Name = "Taj";
	 h.Id = 3;
	 
	 Expect.Call(obj.GetHotel(2)).Return(h).Repeat.Twice();

	 repo.ReplayAll();
	 Assert.AreEqual("Taj", obj.GetHotel(2).Name);
	 Assert.AreEqual(3, obj.GetHotel(2).Id);
	 
	 repo.VerifyAll();
 }
public class TestClassForMockTesting : MyVacations.Tests.ITestClassForMockTesting
{
    public TestClassForMockTesting()
    {

    }
    public IDbConnection DBConn { set { _conn = value; } }
    //constructor for injecting Mock DbConnection
    
    IDbConnection _conn;
    public virtual string Message { get { return Guid.NewGuid().ToString(); } }
    public bool openConnection()
    {
        try
        {
            _conn.Open();
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }

    }

    public Hotel GetHotel(int hotelId)
    {
        List lst = new List();
        DataSet ds = new DataSet();
        IDbDataAdapter odp = new SqlDataAdapter();
        IDbCommand cmd = new SqlCommand("select * from hotel where hotelid =" + hotelId.ToString());

        odp.SelectCommand = cmd;
        odp.SelectCommand.Connection = _conn;
        odp.Fill(ds);
        DataRow row = ds.Tables[0].Rows[0];

        Hotel h = new Hotel();
        h.Id = Convert.ToInt32(row["Id"]);
        h.Name = row["Name"].ToString();
        
        return h;
    }
}

References: http://www.ayende.com/wiki/Rhino+Mocks+Documentation.ashx

Syntax Examples: http://www.ayende.com/wiki/GetFile.aspx?File=Rhino+Mocks+3.3+Quick+Reference.pdf

Advertisements

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

Powered by WordPress.com.

Up ↑

%d bloggers like this: