Introduction
Before getting in detail about Rhino mocks, let's understand what is unit test? why unit testing is required ? And when to use unit test?
- What is unit test?
The code you have written is working as expected is called unit test.
- Why unit testing is required?
Unit testing is required for certain reasons
- The logic or code what you people have written is working as expected.
- Unit testing will give confidence to the developer saying whatever piece of code he/she has written is working as per business rule
- When to use unit test?
As mentioned above, Unit testing is required when the developer wants to verify the logic or business rule is working as expected.In the unit testing,the developer will test for all the possible scenarios and compare if the actual and expected results are the same . if not he\she can take the possible action.
Explanation
Great !! Now we will see how to write Test Case for simple add fuctionality
public class Test
{
public int Add(int value1,int value2)
{
return value1 + value2;
}
}
Here is our Test Case
[TestClass]
public class SampleUnitTest
{
[TestMethod]
public void AddTest_ReturnTrue()
{
int value1 = 7;
int value2 = 7;
var addTest = new Test();
var result = addTest.Add(value1, value2);
Assert.IsTrue(result == 14, "Result of the sum is working as expected");
}
[TestMethod]
public void AddTest_ReturnFalse()
{
int value1 = 7;
int value2 = 7;
var addTest = new Test();
var result = addTest.Add(value1, value2);
Assert.IsFalse(result == 10, "Result of the sum is working not as expected");
}
}
Before going in depth, let's understand what are TestClass,TestMethod attributes and Assert.
- TestClass Attribute: used to identify classes that contains test methods.
- TestMethod Attribute: used to identify test method.
- Assert: Assert class is used to verify conditions in the unit tests using true/false precondition.
In the above example, I used the precondition to verify whether the condition is true/false.
In the above methods, we are using identical code. So now the question, is it better to use common method?The answer is No. In the unit test, one shouldn't worry about creating reusable code.
Though, Unit testing framework supports reusable code to some extent. We can use TestInitialize attribute for reusing the code.
int result;
[TestInitialize]
public void SetUp()
{
int value1 = 7;
int value2 = 7;
var addTest = new Test();
var result = addTest.Add(value1, value2);
}
Lets go through one more example, In this example I'm using 2-tier architecture.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
public class EmployeeDal
{
List<employee> employees = new List<employee> { new Employee { Id = 1, Name = "abc" }, new Employee { Id = 2, Name = "xyz" } };
public Employee GetEmployee()
{
return employees.FirstOrDefault();
}
}</employee>
Here I created a seperate project for data access layer and you can see, I'm not directly interacting with database.
Now lets see what i have written for business logic layer
namespace EmployeeBusinessLayer
{
public class EmployeeBal
{
public string GetEmployee()
{
return new EmployeeDal.EmployeeDal().GetEmployee().Name;
}
}
}
Here just getting name of the employee. Looks simple!!
Now lets look at how the unit test is written
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Employee_ReturnEqual()
{
var employeeBal = new EmployeeBal();
Assert.AreEqual(employeeBal.GetEmployee(), "abc", "Return value is not equal");
}
}
Note: I will be using the same classes of data access layer and business logic layer through out this article and with some modification in the structure.
Looks simple!!. But problem starts now.
There are various disadvantages with the code written above
- Unit test is completely dependent on database(assume EmployeeDal accessing database). If something changes in database unit test will fail.
- We have to do unit testing for our business logic layer not the data access layer.
Now the question arises, how to solve the above problem?
Here is the solution.
There are various framework or test suite available to solve above problem ex: Rhino mocks, fakes etc.
In the above 2-tier example, code is tightly coupled. So we have to use dependency injection which comes under SOLID principle to remove this tight coupling.
Each and every letter of SOLID has its significance. S-> Single responsibility, O-> open and close principle, L-> Linskov substitution principle, L-> Interface segregation principle and D-> Dependency injection or inversion.
This article mainly concentrates on Unit testing and Rhino mocks. You can find the articles on SOLID principle on the internet. I recommend you to read these article on solid principle
http://blog.gauffin.org/2012/05/11/solid-principles-with-real-world-examples/
http://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp -- For beginners
You might soon expect an article on SOLID principle any time. Fingers crossed!!!
Now We are using dependency injection in the 2-tier application code.
Before going in depth about Rhino mocks, let understand what AAA format. AAA is nothing but arrange,act and assert.
- Arrange: Arrange stands for setting up the behavior of mocked class.
- Act: Act stand for executing of test cases.
- Assert: Assert stands for verifying the result.
Through out the article you will use AAA pattern.
Let's begin with Rhino mocks journey. In order to do dependency injection, i have created a new interface in the data access layer as IEmployeeDal.
public interface IEmployeeDal
{
Employee GetEmployee();
}
public class EmployeeDal:IEmployeeDal
{
List<employee> employees = new List<employee> { new Employee { Id = 1, Name = "abc" }, new Employee { Id = 2, Name = "xyz" } };
public Employee GetEmployee()
{
return employees.FirstOrDefault();
}
}</employee>
Changes in the business logic layer as follows.
public class EmployeeBal
{
private IEmployeeDal _employeeDal;
public EmployeeBal(IEmployeeDal employeeDal)
{
_employeeDal = employeeDal;
}
public Employee GetEmployee()
{
return _employeeDal.GetEmployee();
}
}
Now in the unit test project
[TestClass]
public class UnitTest1
{
[TestMethod]
public void Employee_ReturnEqual()
{
var employeeBal = new EmployeeBal(new EmployeeDal.EmployeeDal());
Assert.AreEqual(employeeBal.GetEmployee().Name, "abc", "Return value is not equal");
}
}
When you run this application the test passes. But is it still correct?
My answer is no, because it still accesses data access layer.
Note: In real world application, for the dependency injection use unity container, MEF, structure map etc. For the introduction purpose I'm not using these containers.
Now let's install Rhino mocks on the test project using nuget. After installing you can see Rhino.Mocks.dll in the reference and you can see all the package information in package.config file in the test project.
Now let's see the right way of writing unit test
[TestMethod]
public void Employee_AssertWasCalled()
{
var employeeDalMock = MockRepository.GenerateMock<iemployeedal>();
var employeeBal = new EmployeeBal(employeeDalMock);
employeeBal.GetEmployee();
employeeDalMock.AssertWasCalled(x => x.GetEmployee());
}</iemployeedal>
When you run this test case passes.
Rhino mocks internally uses castle dynamic proxy to generate the proxy when you call GenerateMock<T>(). So everytime the proxy will be generated when you call MockRepository.GenerateMock<T>().
Here in this example, you can see arrange, act and assert pattern is getting used. AssertWasCalled method is used to identify if the particular method has been called or not.
Note: It's a good practice to always use 1 Assert call in the test.
Before going in depth about Rhino mocks. Let's understand the Rhino mocks options
- Strict Mocks: It's a kind of mock that will throw an exception, if any method has not explicity been setup to be used. Generally we use strict mocks to verify all the exceptions.
- Dynamic Mock: It's a kind of mock that will not throw any excetion, if any method is not set up and it will return default value as null for the method. In the above example, we already used mock mechanism.
- PartialMocks: Partial mock is also like a dynamic mock that will not throw any exception. But instead of sending default as null like dynamic mock, it will return the actual value of the implementation. Mainly we use partial mock while accessing the abstract class. You can find the source for partial mock in the attached source code.
Let's take another example of how to use stub.
public interface IEmployeeDal
{
Employee GetEmployee();
string GetEmployeeById(int id);
}
public class EmployeeDal:IEmployeeDal
{
List<employee> employees = new List<employee> { new Employee { Id = 1, Name = "abc" }, new Employee { Id = 2, Name = "xyz" } };
public Employee GetEmployee()
{
return employees.FirstOrDefault();
}
public string GetEmployeeById(int id)
{
return employees.FirstOrDefault(x => x.Id == id).Name;
}
}
public class EmployeeBal
{
private IEmployeeDal _employeeDal;
public EmployeeBal(IEmployeeDal employeeDal)
{
_employeeDal = employeeDal;
}
public Employee GetEmployee()
{
return _employeeDal.GetEmployee();
}
public string GetEmployeeById(int id)
{
return _employeeDal.GetEmployeeById(id);
}
}
[TestMethod]
public void Employee_AreEqual()
{
var employeeDalMock = MockRepository.GenerateMock<iemployeedal>();
employeeDalMock.Stub(x => x.GetEmployeeById(1)).Return("abc");
var employeeBal = new EmployeeBal(employeeDalMock);
var result = employeeBal.GetEmployeeById(1);
Assert.AreEqual(result, "abc", "value is not abc");
}</iemployeedal>
In this example, we are telling rhino mocks to return value as "abc" when GetEmployeeById method is called in the data access layer.
In the above example you can see, I'm passing the value of Id as 1. Id=1 is not required because we are telling rhino mocks to return value as "abc" irrespective of anything but still we have to pass some integer value. Correct?
That's the reason, Rhino mocks came with the future called Rhino mock constraints.
Now see how we can modify it.
[TestMethod]
public void Employee_AreEqual()
{
var employeeDalMock = MockRepository.GenerateMock<iemployeedal>();
employeeDalMock.Stub(x => x.GetEmployeeById(Arg<int>.Is.Anything)).Return("abc");
var employeeBal = new EmployeeBal(employeeDalMock);
var result = employeeBal.GetEmployeeById(Arg<int>.Is.Anything);
Assert.AreEqual(result, "abc", "value is not abc");
}</int>
Instead of id as 1, we are using Arg<int>.Is.Anything. It means any value.
hope the article helped you!!