This blog will demonstrates
how to write the unit test for business object and how to use Moq framework to mock
the
unit code or dependency of business object and how the DI makes testable unit of code.
basically Unit Test is used to test the unit of work i.e. method and a good unit test should
not cross class boundaries and it certainly should not cross network boundaries
to access external resource such as Database.
Practicing writing
of unit test always enforce to better design and quality of code and also it
reduce the cost of project. You can read more benefit
of unit testing
We should design service/component so carefully, it should be testable. If your service have any dependency and it should be abstracted and replaced by interface and resolved by DI.
Here is a business
Object – TulipBusiness, which has a method to get yearly sales figure
Abstract Type – Interface
public interface ITulipBusiness
{
decimal GetTulipAnnualSales(int year);
}
Concreate Class
public class TulipBusiness : ITulipBusiness
{
ITulipRepository _tulipRepository;
public TulipBusiness(ITulipRepository
tulipRepository)
{
_tulipRepository
= tulipRepository;
}
public decimal GetTulipAnnualSales(int year)
{
decimal salesAmount =
_tulipRepository.GetTulipYearSales(year);
if(salesAmount == 0)
{
throw new Exception("No Sales Found");
}
return salesAmount;
}
}
In above class, we
can see business object depends on repository object to make database call and
get yearly sales figure.
As per DI rule,
the dependency ‘TulipRepository’ should
be abstract and replaced by interface ‘ITulipRepository’
Abstract Type – Interface
public interface ITulipRepository
{
decimal GetTulipYearSales(int year);
decimal GetTulipMonthlySales(int year);
}
Concreate Class
public class TulipRepository : ITulipRepository
{
public decimal GetTulipMonthlySales(int year)
{
throw new NotImplementedException();
}
public decimal GetTulipYearSales(int year)
{
throw new NotImplementedException();
}
}
TulipRepository repository class will be responsible to make database call and get
yearly sales figure but it is not implemented yet.
But if you see business
class, the dependency
of TulipBusiness class is already replaced by interface ITulipRepository and now can easily code
the business object based on ITulipRepository
type and with help of Moq framework, we can easily mock the repository class
behavior and write the unit test for business class.
Here are few basic unit tests of Business class
[TestClass]
public class TulipBusinessTest
{
TulipBusiness business;
Mock _repository;
[TestInitialize]
public void init()
{
_repository = new Mock(MockBehavior .Strict);
// Mocking Repository Class Methods
_repository.Setup(x => x.GetTulipYearSales(2014)).Returns(1050.0M);
_repository.Setup(x => x.GetTulipYearSales(2015)).Returns(1250.0M);
// For 2016 Years, No Sales
_repository.Setup(x => x.GetTulipYearSales(2016)).Returns(0);
// Initlize the business object and inject mocked repostory object
through constructor
business = new TulipBusiness(_repository.Object);
}
[TestMethod]
public void GetTulipSales_20014()
{
decimal result =
business.GetTulipAnnualSales(2014);
// expected value, as per mock should be 1050.0M
Assert.AreEqual(result, 1050.0M);
}
[TestMethod]
public void GetTulipSales_20015()
{
decimal result =
business.GetTulipAnnualSales(2015);
// expected value, as per mock should be 1250.0M
Assert.AreEqual(result, 1250.0M);
}
[TestMethod]
public void GetTulipSales_2016()
{
// expecting Exception
Assert.ThrowsException<Exception>(() =>
business.GetTulipAnnualSales(2016));
}
}
In above unit test
for business class TulipBusiness, Moq framework is allowed us to create the
mimic behavior of Repository object.
Example:
_repository = new Mock(MockBehavior .Strict);
_repository.Setup(x
=> x.GetTulipYearSales(2014)).Returns(1050.0M);
GetTulipYearSales
method of ITulipRepository repository type is mocked and it always return
1050.0 sales figure, when we pass year as 2014 and in this way we can easily
write the unit test and run the unit test without making any database call.
Here is unit test result:
Other
posts related to DI:
Happy Testing!!
No comments:
Post a Comment