Unit Testing is an important aspect of software development according to most developers.However, there are people on the other side who think that unit test cases are wastage of time as you cannot always mimic or catch all of the real life/production environment scenarios in development environment.

I don’t want to choose sides. The best approach is stick to whatever you like. If you don’t like writing unit test cases then don’t go for it. If however it’s mandatory for your project then please go for it. In this post i’ll show you how to write good test cases . There are tons of article as how to do unit testing of websites,MVC project etc.But this post is different from them.Here i’ll show how to write unit test for individual methods of different types.

In C# we generally do unit testing using MS Unit test and in some projects we use NUnit. But as per my Opinion it is best to use features of both the frameworks to write unit test cases.In our project we would be using NUnit test methods and use some of the features of Microsoft unit test in between. Moq has been used as a mocking framework.In our sample project we would be testing a class TestingDemo\DemoTest\Demonstration.cs .The unit tests are written in “testingdemo\unittestdemo\unittest1.cs“

public function : let’s first see how to write unit test case for public method .

we have a function “Add“

public int Add(int x, int y) { return x + y; }

The unit testing function for the above function is:

[Test, TestCaseSource("AddTestCases")] public void Check_Add(AddTestData testData) { //Arrange Demonstration obj = new Demonstration(); //Act var result = obj.Add(testData.X, testData.Y); //Assert NUnit.Framework.Assert.AreEqual(testData.ExpectedResult, result, "testing of ADD function has failed for these parameters"); }

The accompanying function AddTestCases is written below:

private static List<AddTestData> AddTestCases() { ///various test scenarios List<AddTestData> lstAddDatas = new List<AddTestData>(); //input parameters all +ve lstAddDatas.Add(GetSingleAddData(1, 2, 3)); //input parameters one +ve one -ve lstAddDatas.Add(GetSingleAddData(-1, 2, 1)); //input parameters all -ve lstAddDatas.Add(GetSingleAddData(-1, -2, -3)); return lstAddDatas; }

Also the struct AddTestData used in this function is shown below:

public struct AddTestData { public int X; public int Y; public int ExpectedResult; }

In the main Nunit unit test function “Check_Add” as you can see there is an annotation :

[Test, TestCaseSource("AddTestCases")]

“TestCaseSource(“AddTestCase”)” denotes that the various unit test scenarios or test cases that are there in the function “AddTestCases“. This is the best way of writing or mentioning various test parameters. Otherwise the unit test function would look cluttered with multiple annotations containing various scenario which is the standard way of writing scenarios in test cases in Microsoft unit testing these days. Or even most of the time we just write one test scenario which is writing test case just for the sake of writing a test case.Best way is to leverage NUnit’s capability of mentioning “TestCaseSources” to write all test scenarios within one function.

If we see the function “TestCaseSource(“AddTestCase”)”

private static List<AddTestData> AddTestCases()

Here we have various test scenarios written and each test scenario represented by “AddTestData” struct. In the struct, x and y represent inputs and “ExpectedResult” literally means the same 🙂

We have used struct instead of class because it’s lightweight.

and if you again check the main test function: “Check_Add” you will see that it takes “AddTestData” as an input parameter.’In “Check_Add” function i.e main testing function it is always a good practice to segregate the function in 3 Parts – AAA .i.e. Arrange, Act and Assert as shown in the function.

By writing test case in this manner what we have achieved is that we can add as many test scenarios in the “AddTestCases” function without cluttering the main test function with annotations after annotations. Thus we keep our code extensible and as well as clean and simple.

2. Private function : Here I’ll demonstrate how to write test cases for private function.The private function “Multiply” to be tested is shown below:

private int Multiply(int x, int y) { return x * y; }

The unit testing function for the above function is:

[Test, TestCaseSource("MultiplyTestCases")] public void Check_Multiply(AddTestData testData) { //Arrange PrivateObject obj = new PrivateObject(new Demonstration()); //Act var result = obj.Invoke("Multiply", testData.X, testData.Y); //Assert NUnit.Framework.Assert.AreEqual(testData.ExpectedResult, result, "testing of multiply function has failed for these parameters"); }

The accompanying test functions are shown below:

private static List<AddTestData> MultiplyTestCases() { ///various test scenarios List<AddTestData> lstAddDatas = new List<AddTestData>(); //input parameters all +ve lstAddDatas.Add(GetSingleAddData(1, 2, 2)); //input parameters one +ve one -ve lstAddDatas.Add(GetSingleAddData(-1, 2, -2)); //input parameters all -ve lstAddDatas.Add(GetSingleAddData(-1, -2, 2)); // one input zero lstAddDatas.Add(GetSingleAddData(0, 5, 0)); return lstAddDatas; }

Also we use the same struct AddTestData for input parameters.In the main Unit function you can see the way the class or object is instantiated is slightly different

//Arrange PrivateObject obj = new PrivateObject(new Demonstration()); //Act var result = obj.Invoke("Multiply", testData.X, testData.Y); //Assert NUnit.Framework.Assert.AreEqual(testData.ExpectedResult, result, "testing of multiply function has failed for these parameters");

In the “Arrange” part of logic privateObject is being used to instantiate object. This is not a part of NUnit framework but rather MS Unit test.

After that in the “Act” segment we can see the function “Multiply” is invoked.

3. Public static function: Here I’ll explain how to test a public static function.

We have a function “IsEven” for which unit test needs to be written.The code is shown below:

public static bool IsEven(int x) { return (x % 2 == 0); }

The unit testing function for the above function is:

[Test, TestCaseSource("IsEvenTestCases")] public void Check_IsEven(KeyValuePair<int, bool> testData) { //Arrange //Act var result = Demonstration.IsEven(testData.Key); //Assert NUnit.Framework.Assert.AreEqual(testData.Value, result, "testing of IsEven function has failed for the parameter"); }

The accompanying test functions are shown below:

private static Dictionary<int, bool> IsEvenTestCases() { ///various test scenarios ///key contains the test input parameter // value contains the expected result Dictionary<int, bool> dcIsEvenCases = new Dictionary<int, bool>(); // -ve no scenarios dcIsEvenCases.Add(-1, false);//odd dcIsEvenCases.Add(-2, true);//even dcIsEvenCases.Add(-3, false);//odd dcIsEvenCases.Add(0, true);//even // +ve no scenarios dcIsEvenCases.Add(1, false);//odd dcIsEvenCases.Add(2, true);//even dcIsEvenCases.Add(3, false);//odd return dcIsEvenCases; }

In the Unit test case for public static function if you see I have kept the “Arrange” part of logic empty and in the “Act” segment I directly invoke the function (just as a static function is invoked) “IsEven”. And then, usual Assert scenarios are written.

4. Private static function : Here I’ll explain how to test a private static function.

We have a function “CalculatePercentage” for which unit test needs to be written.The code is shown below:

private static decimal CalculatePercentage(int x, int y) { decimal percentage = (x * 100) / y; return percentage; }

The unit testing for above function is:

[Test, TestCaseSource("CalPercentageTestCases")] public void check_CalculatePercentage(CalculatePercentageData calPercentageData) { //Arrange PrivateType privateType = new PrivateType(typeof(Demonstration)); //Act var result = (decimal)privateType.InvokeStatic("CalculatePercentage", calPercentageData.X, calPercentageData.Y); //Assert NUnit.Framework.Assert.AreEqual(calPercentageData.ExpectedResult, result, "testing of CalculatePercentage function has failed for this parameter"); }

The accompanying test functions are shown below:

private static List<CalculatePercentageData> CalPercentageTestCases() { ///various test scenarios List<CalculatePercentageData> lstCalPercentageDatas = new List<CalculatePercentageData>(); //scenario: x < y lstCalPercentageDatas.Add(GetSingleCalPercentageData(2, 10, 20)); //scenario : x = 0 lstCalPercentageDatas.Add(GetSingleCalPercentageData(0, 10, 0)); //scenario: x > y lstCalPercentageDatas.Add(GetSingleCalPercentageData(8, 2, 400)); return lstCalPercentageDatas; }

private static CalculatePercentageData GetSingleCalPercentageData(int x, int y, int result) { CalculatePercentageData singleData = new CalculatePercentageData(); singleData.X = x; singleData.Y = y; singleData.ExpectedResult = result; return singleData; }

Also the struct “CalculatePercentageData” used as an input parameter in the function is as follows:

public struct CalculatePercentageData { public int X; public int Y; public decimal ExpectedResult; }

In the Unit test case for private static function “check_CalculatePercentage” if you see the “Arrange” part of logic,the instantiation of the class is a bit different as shown below:

PrivateType privateType = new PrivateType(typeof(Demonstration));

and in the “Act” segment the function is invoked in a different way as shown below:

var result = (decimal)privateType.InvokeStatic("CalculatePercentage", calPercentageData.X, calPercentageData.Y);

So here in the “Arrange” and “Act” segment we have used objects in MS unit test. And then, usual Assert scenarios are written.

5. Public void function updating a private variable at the class level : The function “SetWholeNo” takes a list of nos as input and saves the whole nos into a new list variable “lstwholeNo” defined at the class level.The code is shown below:

private void SetWholeNo(List<int> lstNos) { foreach (var no in lstNos) { if (no >= 0) { lstwholeNo.Add(no); } } }

The unit testing for the above function is:

[Test ,TestCaseSource("SetWholeNoCases")] public void Check_SetWholeNo(SetWholeNoData testData) { //Arrange PrivateObject obj = new PrivateObject(new Demonstration()); //Act and Assert NUnit.Framework.Assert.DoesNotThrow(() => obj.Invoke("SetWholeNo", testData.lstNos)); ///fetching the value of class level private variable var result = (List<int>)obj.GetField("lstwholeNo"); foreach (int actualNo in result) { NUnit.Framework.Assert.Contains(actualNo, testData.lstExpectedWholeNos, "testing of SetWholeNo function has failed"); } }

The accompanying test functions are shown below:

private static List<SetWholeNoData> SetWholeNoCases() { ///various test scenarios List<SetWholeNoData> lstCases = new List<SetWholeNoData>(); SetWholeNoData normalCase = new SetWholeNoData(); normalCase.lstNos = new List<int> { -2, -1, 0, 1, 2, 3 }; normalCase.lstExpectedWholeNos = new List<int> { 0, 1, 2, 3 }; lstCases.Add(normalCase); return lstCases; } }

Also the struct “SetWholeNoData” used as an input parameter in the function is as follows:

public struct SetWholeNoData { public List<int> lstNos; public List<int> lstExpectedWholeNos; }

The main thing to remember is in a void function since it doesn’t return any value, so you can’t do the usual way of comparing the actual result with expected result instead of that you will do it indirectly or other way.If you see the “Arrange” and “ACT and Assert” section of the function “Check_SetWholeNo” ,the instantiation is done as a private object

PrivateObject obj = new PrivateObject(new Demonstration());

and then the rest part is done as follows:

//Act and Assert NUnit.Framework.Assert.DoesNotThrow(() => obj.Invoke("SetWholeNo", testData.lstNos)); ///fetching the value of class level private variable var result = (List<int>)obj.GetField("lstwholeNo");

The function is invoked and then we do an Obj.GetField(“lstwhole”) to fetch the value of the variable lstwholeNo and then do the comparison of the values stored in this variable and that’s how the testing is done.

Another thing there is a good feature in MS Unit Test known as [DeloymentItem] . Unfortunately this feature is not yet available in NUnit test cases.But there is a way to mimic this feature in Nunit .The details of this implementation can be found in many sites.I’m just sharing the link of one such site here.

I think in this post I have covered sufficient scenarios to get you started.Let’s hope with this you can start writing better unit test cases.It doesn’t matter whether you write unit tests before or after writing your code(I know this is quite a touchy topic).

You can download the source code from my github repository. Feel free to give comments if you find any mistakes/ improvement in my post.Also if you feel like contributing to my repository feel free to create a pull request.