Introduction
Today, when applications are getting more and more complex, it is very difficult for a developer to check all scenarios while creating or editing functionality. Therefore, a separate Unit Testing project is a must to make sure all desired functional parameters are met and nothing is being missed. To make it happen, sometimes data is mocked and conditional asserts are applied to validate the functional requirement. This tip is going to throw some light on how to implement unit testing into a .NET application using Moq
, NUnit
and Shouldly
.
Background
NUnit
has been there for a long time but some critical must have functionalities were missing viz data mocking where response from some external functionality is to be mocked using Moq
to test a given functionality and Shouldly
to make asserts more understanding and meaningful.
Both Moq
and Shouldly
are available as nuget packages.
Using the Code
To show how Mocking for a function is done, Moq
is used to setup a given function to return predefined responses based on certain conditions.
Shouldly
provides readymade wrapper functions to assert acceptable conditions.
[Test]
public void TestGetRailwayStationById()
{
var mockClassBll = new Mock<IBll>();
mockClassBll.Setup(c => c.GetRailwayStationById(It.IsAny<int>()))
.Returns(new RailwayStationDs(1, "New Delhi"));
var objRailwayStation = new RailwayStation(mockClassBll.Object);
var result = objRailwayStation.GetRailwayStationById(1);
result.ShouldNotBeNull();
result.StationName.ShouldNotBeEmpty();
}
[Test]
public void TestGetRailwayStationByString()
{
var mockClassBll = new Mock<IBll>();
mockClassBll.Setup(c => c.GetRailwayStationByName(It.IsAny<string>()))
.Returns(new RailwayStationDs(1, "New Delhi"));
var objRailwayStation = new RailwayStation(mockClassBll.Object);
var result = objRailwayStation.GetRailwayStationByName("New Delhi");
result.ShouldNotBeNull();
result.StationId.ShouldBeGreaterThan(0);
}
Unit Test Complex Functions with Saved Input Parameters and Output
In applications, there are few very complex functions which return different results based on lot of cases within them and it is very difficult to check all those cases, therefore the best way to unit test such functions would be to save all input parameters and their expected outputs. Such test data can be saved either in database or in XML files and can be used again and again during unit testing to validate all cases. Such test data is best suited for conditions when such complex functions are edited and unknowingly one or more case’s functionality alters and returns wrong result.
[TestMethod]
[DataSource("System.Data.SqlClient",
@"Data Source=SAURABH\ADVANCE;Initial Catalog=TestDB;
Integrated Security=True", "dbo.StatusTestData",
DataAccessMethod.Sequential)]
public void TestStatusDataDrivenSQL()
{
TestContext.ShouldNotBeNull();
var strTime = TestContext.DataRow["Time"].ToString();
var varTime = TimeSpan.Parse(strTime);
var varStatus = TestContext.DataRow["Status"].ToString();
var objBll = new ClassBLL1();
var result = objBll.CurrentStatus(varTime);
result.ShouldNotBeNullOrEmpty();
result.ShouldBe(varStatus);
}
[TestMethod]
[DeploymentItem(".\\UnitTestBLL\\XMLTestCases.xml")]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
@"XMLTestCases.xml", "case", DataAccessMethod.Sequential)]
public void TestStatusDataDrivenXML()
{
TestContext.ShouldNotBeNull();
var strTime = TestContext.DataRow["Time"].ToString();
var varTime = TimeSpan.Parse(strTime);
var varStatus = TestContext.DataRow["Status"].ToString();
var objBll = new ClassBLL1();
var result = objBll.CurrentStatus(varTime);
result.ShouldNotBeNullOrEmpty();
result.ShouldBe(varStatus);
}