Click here to Skip to main content
15,886,873 members
Articles / Programming Languages / C#

Using MS Test with .NET Core API

Rate me:
Please Sign up or sign in to vote.
4.33/5 (2 votes)
23 Jul 2017CPOL2 min read 21.3K   7   4
This article describes how to test your .NET core API using MS Test.

Introduction

.NET Core is now the default standard for any web application development in the .NET world. However, with every application development, it is important to unit test your code.

Fortunately, .NET core has excellent support for MS Test. This article describes how you can use MS Test to write unit test cases for your API.

Why MS Test, Why Not xUnit?

xUnit is an excellent test framework but I found it lacks features which we are used to over the years while writing test cases with MS Test. One of the major limitations with xunit is that it does not do anything similar to AssemblyInitialize, which is where we initialize anything before any of the test cases are executed.

I use AssemblyInitialize to register my DI for other global initialization. If you are like me who likes to initialize test projects, MS Test is the default choice.

.NET core has excellent support for MS Test.

Using the Code

I am using Visual Studio 2017 for creating my API project and writing MS Test cases. Follow the below steps to write MS Test cases:

  1. Add a new project of type "Unit Test Project (.NET Core)" to your solution.

    Image 1

  2. Add reference to other projects in your solution.
  3. Add nuget package "Microsoft.AspNetCore.TestHost". Add "Moq" nuget package if you would like to use mocking.

    Image 2

  4. Create a copy of Startup.cs from your main API project into your test project. I have renamed it to "TestStartup.cs" just so that I don't accidentally touch the main Startup.cs.
  5. Add a TestInitializer.cs (rename the class to whatever you like) in your test project.
  6. Add the logic to start test server and register the mock repositories.
    C#
    [TestClass]
    public class TestInitializer
    {
        public static HttpClient TestHttpClient;
        public static Mock<IEmployeeRepository> MockEmployeeRepository;
    
        [AssemblyInitialize]
        public static void InitializeTestServer(TestContext testContext)
        {
            var testServer = new TestServer(new WebHostBuilder()
               .UseStartup<TestStartup>()
               // this would cause it to use StartupIntegrationTest class
               // or ConfigureServicesIntegrationTest / ConfigureIntegrationTest
               // methods (if existing)
               // rather than Startup, ConfigureServices and Configure
               .UseEnvironment("IntegrationTest"));
    
            TestHttpClient = testServer.CreateClient();
        }
    
        public static void RegisterMockRepositories(IServiceCollection services)
        {
            MockEmployeeRepository = (new Mock<IEmployeeRepository>());
            services.AddSingleton(MockEmployeeRepository.Object);
    
            //add more mock repositories below
        }
    }
    
  7. From "ConfigureServices" of TestStartup.cs, call method to initialize your repositories.
    C#
    public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            ....
            //Mock your repositories.
            TestInitializer.RegisterMockRepositories(services);
            ....
        }
    
  8. Write your first test case:
    C#
    [TestClass]
    public class TestEmployee
    {
        [TestMethod]
        public void TestGetAllEmployees()
        {
            var mockEmps = new List<Employee>();
            mockEmps.Add(new Employee
            { EmpId = 1, FirstName = "F1", LastName = "L1", Email = "F1.L1@tt.com" });
            mockEmps.Add(new Employee
            { EmpId = 2, FirstName = "F2", LastName = "L2", Email = "F2.L2@tt.com" });
    
            var employeeRepositoryMock = TestInitializer.MockEmployeeRepository;
            employeeRepositoryMock.Setup
                  (x => x.GetEmployees()).Returns(Task.FromResult(mockEmps));
    
            var response = TestInitializer.TestHttpClient.GetAsync("api/Employees").Result;
    
            var resp = response.Content.ReadAsStringAsync().Result;
            var responseData = JsonConvert.DeserializeObject<List<Employee>>(resp);
            Assert.AreEqual(3, responseData.Count);
            Assert.AreEqual(mockEmps[0].EmpId, responseData[0].EmpId);
        }
    }
    
  9. You can now debug/run your test case and view the results in Test Explorer.

Ponts of Interest

It is a good practice not to have any other code in controllers that make the call to your business logic layer. People tend to write test cases just for their business logic as they feel the controller doesn't have any code. I prefer writing test cases that call the controller as it traverses the full hierarchy.

You can download the sample code from below this github link.

One major limitiation is that Visual Studio doesn't support code coverage for .NET core projects, which is detailed at this link. It appears that Update 3 of Visual Studio 2017 does support code coverage but I didn't get a chance to download and play with Update 3. One option to get code coverage for .NET core projects is to use open source opencover.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
SuggestionSome observations about testing Pin
John Brett24-Jul-17 4:56
John Brett24-Jul-17 4:56 
GeneralRe: Some observations about testing Pin
Praveenkj7924-Jul-17 19:25
Praveenkj7924-Jul-17 19:25 
GeneralRe: Some observations about testing Pin
John Brett25-Jul-17 2:26
John Brett25-Jul-17 2:26 
GeneralRe: Some observations about testing Pin
Praveenkj7925-Jul-17 19:00
Praveenkj7925-Jul-17 19:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.