Unit Testing in ASP.NET Core using MSTest Framework: Tutorial

unit testing in asp.net core using MSTest framework
Ajay Thakor
02-Jan-2023
Reading Time: 7 minutes

In this tutorial article, we’ll learn how to do unit testing in ASP.NET Core using MSTest framework.

What is Unit Testing?

Unit testing is a type of software testing that examines individual units (components) of software. The goal of unit testing is to ensure that each component of the software works as intended. A unit is the smallest testable component of any piece of software.

The unit tests with asp.net core support three different test frameworks: MSTest, xUnit, and NUnit, which enable us to test our code consistently. I’ll go over unit testing in ASP.NET Core using MSTest in this article. Microsoft’s MSTest is a unit-testing library. It supports all.NET programming languages.

We can put tests in the same project directory or in a separate directory. Let’s understand by simple example.

Prerequisites:

1. Prior knowledge of C#
2. Prior knowledge of .NET Core
3. Visual Studio 2019

Step by step tutorial on Unit Testing using MSTest Framework

Step 1: Create a New Web API Project

  • Start up Visual studio
  • Choose Asp.net Web Application (C#)
  • After that you will have to configure your project

Here, Application Name: UnitTestDemo

Step 2: Add a New Service folder and add services file inside folder

Create a new Service class. Here, we have created MessageService.cs file and added simple message functions which are return simple message in string data type.

Here MessageService.cs file created and added simple message functions which are return simple message in string data type.

And, Write code inside MessageService.cs file like below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace UnitTestDemo.Services
{
    public class MessageService
    {
        public Func<string> msg1 = () => "Hello there!";
        public Func<string> msg2 = () => "Good Morning!";        
    }
}

Now, Let’s add MSUnit test library. Right click on solution >> Add >> Add new project >> select project.

Let’s add MSUnit test library

After Adding MSTest project our solution file will look like below:

MessageTest.cs Unit Testing in ASP.NET Core using MSTest Framework: Tutorial

Also, Add project reference of “UnitTestDemo” to “TestDemo”, after that you will able to use Methods from MessageService file.

Create test class(MessageTest.cs), add below code to this file.

using Microsoft.VisualStudio.TestTools.UnitTesting;
using UnitTestDemo.Services;

namespace TestDemo
{
    [TestClass]
    public class MessageTest
    {
        private const string Expected1 = "Hello there! Test!!!";
        private const string Expected2 = "Good Morning!";

        MessageService message = new MessageService();

        [TestMethod]
        public void Message1()
        {
            var m1 = message.msg1();

            Assert.AreEqual(Expected1, m1);
        }

        [TestMethod]
        public void Message2()
        {
            var m2 = message.msg2();

            Assert.AreEqual(Expected2, m2);
        }
    }
}

In the above (MessageTest.cs) file, we have created two test method to validate service method from MessageService file.

The class is annotated with the [TestClass] attribute, the test methods are annotated with the [TestMethod] attribute. We use assertions to ensure the correct output.

Here, The assert method is one of the most effective methods to detect logic errors at runtime and making it easy to correct the error at the production level.

Assert.AreEqual(arg1, arg2), method check applied both are same, if same then it will be fine, and throws an exception if the two objects are not equal. Now, Let’s run our test cases and check our test will be passing or not.

We can run test case by right click on testCase (MessageTest.cs) file and select Run Tests:

Run test case by right click on TestCase

As you click on “Run Tests”, all test method of this file will run and check whether service method are working proper or not and according to it, will give result at the bottom of visual studio.

Test run finished, total 2 tests has been done, and both are passed, 0 fail and 0 skipped

As we can see above, Test run finished, total 2 tests has been done, and both are passed, 0 fail and 0 skipped.

Let’s try by something change, I’m changing Expected1 string and replace to it “Hello there! Test!!!”.

Now, our return result from service file and expected result in test file are different, in this case testmethod 1 would be failed.

Let’s check:

See above, TestMethod1(Message1) is failed.

So, in that way test cases are working and we can validate our method logic before implementation on production.

Step 3: C# ASP.NET Core MSTest parameterized tests

Now, Let’s test parameterized method from service file, for that we need to create a new service file(ArithService.cs).

Create a new service file(ArithService.cs)

And Add below code to the ArithService.cs file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace UnitTestDemo.Services
{
    public class ArithService
    {
        public Func<int, int, int> add = (a, b) => a + b;
        public Func<int, int, int> mul = (a, b) => a * b;
        public Func<int, int, int> sub = (a, b) => a - b;
        public Func<int, int, int> div = (a, b) => a / b;
    }
}

Now, Create a new test case file for testing methods of Arith Service.

Create a new test case file for testing methods of Arith Service

Now, Let’s add Test Methods to the ArithTest.cs file. Like below:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using UnitTestDemo.Services;

namespace TestDemo
{
    [TestClass]
    public class ArithTest
    {
        ArithService arith = new ArithService();

        [DataTestMethod]
        [DataRow(1, 2, 3)]
        [DataRow(2, 2, 4)]
        [DataRow(-1, 4, 3)]
        public void Add(int x, int y, int expected)
        {
            int r = arith.add(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DataRow(1, 2, -1)]
        [DataRow(2, 2, 0)]
        [DataRow(3, 2, 1)]
        public void Sub(int x, int y, int expected)
        {
            int r = arith.sub(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DataRow(9, 3, 27)]
        [DataRow(3, 3, 9)]
        [DataRow(-3, -3, 9)]
        [Ignore]
        public void Mul(int x, int y, int expected)
        {
            int r = arith.mul(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DataRow(9, 3, 3)]
        [DataRow(3, 3, 1)]
        [DataRow(8, 2, 4)]
        [Ignore]
        public void Div(int x, int y, int expected)
        {
            int r = arith.div(x, y);
            Assert.AreEqual(r, expected);
        }
    }
}

Use assembly reference of
using Microsoft.VisualStudio.TestTools.UnitTesting;.

Here, we test each method with three sets of values.
We are testing the all methods with three sets of values given by the [DataRow] attribute. The calculated and expected values are compared with Assert.AreEqual assertion.

Run the test case:

Calculated and Expected Values are compared with Assert.AreEqual assertion

So, we can see above all tests are passed. In that way we can test parameterized method.

Step 4: C# ASP.NET Core MSTest skipping tests

Suppose, if you want to ignore some method from test for now, so Test methods can be skipped with [Ignore] attribute.

Let’s see how?

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UnitTestDemo.Services;

namespace TestDemo
{
    [TestClass]
    public class ArithDynamicDataTest
    {
        ArithService arith = new ArithService();

        [DataTestMethod]
        [DynamicData(nameof(AddData), DynamicDataSourceType.Method)]
        public void Add(int x, int y, int expected)
        {
            int r = arith.add(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(SubData), DynamicDataSourceType.Method)]
        public void Sub(int x, int y, int expected)
        {
            int r = arith.sub(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(MulData), DynamicDataSourceType.Method)]
        public void Mul(int x, int y, int expected)
        {
            int r = arith.mul(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(DivData), DynamicDataSourceType.Method)]
        public void Div(int x, int y, int expected)
        {
            int r = arith.div(x, y);
            Assert.AreEqual(r, expected);
        }

        private static IEnumerable<object[]> AddData()
        {
            return new[]
            {
            new object[] { 1, 2, 3 },
            new object[] { 2, 2, 4 },
            new object[] { -1, 4, 3 }
        };
        }

        private static IEnumerable<object[]> SubData()
        {
            return new[]
            {
            new object[] { 1, 2, -1 },
            new object[] { 2, 2, 0 },
            new object[] { 3, 2, 1 }
        };
        }

        private static IEnumerable<object[]> MulData()
        {
            return new[]
            {
            new object[] { 9, 3, 27 },
            new object[] { 3, 3, 9 },
            new object[] { -3, -3, 9 }
        };
        }

        private static IEnumerable<object[]> DivData()
        {
            return new[]
            {
            new object[] { 9, 3, 3 },
            new object[] { 3, 3, 1 },
            new object[] { 8, 2, 4 }
        };
        }
    }
}

In the above file, I have added [Ignore] attribute in two test method. It will ignore these two method from test.

Let’s run tests and check output:

Ignore attribute Unit Testing in ASP.NET Core using MSTest Framework: Tutorial

So, As you can see here, 8 passed and 2 skipped out of 10 tests. In this way we can ignore method from test.

Step 5: C# ASP.NET Core MSTest DynamicData

Let’s create another test file for DynamicData test cases. And added code like below:

With [DynamicData] attribute, we can externalize the test data into a method or a property.

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UnitTestDemo.Services;

namespace TestDemo
{
    [TestClass]
    public class ArithDynamicDataTest
    {
        ArithService arith = new ArithService();

        [DataTestMethod]
        [DynamicData(nameof(AddData), DynamicDataSourceType.Method)]
        public void Add(int x, int y, int expected)
        {
            int r = arith.add(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(SubData), DynamicDataSourceType.Method)]
        public void Sub(int x, int y, int expected)
        {
            int r = arith.sub(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(MulData), DynamicDataSourceType.Method)]
        public void Mul(int x, int y, int expected)
        {
            int r = arith.mul(x, y);
            Assert.AreEqual(r, expected);
        }

        [DataTestMethod]
        [DynamicData(nameof(DivData), DynamicDataSourceType.Method)]
        public void Div(int x, int y, int expected)
        {
            int r = arith.div(x, y);
            Assert.AreEqual(r, expected);
        }

        private static IEnumerable<object[]> AddData()
        {
            return new[]
            {
            new object[] { 1, 2, 3 },
            new object[] { 2, 2, 4 },
            new object[] { -1, 4, 3 }
        };
        }

        private static IEnumerable<object[]> SubData()
        {
            return new[]
            {
            new object[] { 1, 2, -1 },
            new object[] { 2, 2, 0 },
            new object[] { 3, 2, 1 }
        };
        }

        private static IEnumerable<object[]> MulData()
        {
            return new[]
            {
            new object[] { 9, 3, 27 },
            new object[] { 3, 3, 9 },
            new object[] { -3, -3, 9 }
        };
        }

        private static IEnumerable<object[]> DivData()
        {
            return new[]
            {
            new object[] { 9, 3, 3 },
            new object[] { 3, 3, 1 },
            new object[] { 8, 2, 4 }
        };
        }
    }
}

In above file, we provide data for testing from separate methods using [DynamicData] attribute.

Output:

Run tests:

Data for testing from separate methods using [DynamicData] attribute

So, Above tutorial is about to how to use MSTest Unit testing in ASP.NET Core.

That’s it. Over To You!

Looking for a Sample Source Code? Here you go: GitHub.

Furthermore, professional assistance may be necessary if you’re dealing with enterprise software or large-scale applications. Get in touch with us to hire dot net developers who have worked on enterprise applications for at least 5 years.

Posted in .NET Development