Card image cap

CI/CD Getting Started - Automating Test and Reporting on ASP.NET Core Build using Jenkins

This is the fourth article in the CI/CD using Jenkins series, wherein we setup automation of fetch, build, test and deploying any codebase using Jenkins automation server and we have been looking at a particular usecase of automating the various stages of an aspnetcore codebase for our understanding. So far we have seen how to fetch an aspnetcore codebase from a Git repository, how to automate the build of the fetched codebase and generate build artifacts. In this article we shall look at how we can automate executing test scripts on our fetched codebase after a build and generate a report out of it.

We shall first start by refactoring our existing codebase (a single API project ReadersApi.csproj) and bringing it under a solution file for our maintainability. Since we are using aspnetcore for demonstration, we can make things easier by using the dotnet core CLI to add a new solution file. I shall move all the ReadersApi project files under a sub directory Readers.Api and then under the root directory i shall open a command terminal (or command prompt) and shall add a new solution by the below command.


> dotnet new sln --name ReadersApi

This shall an empty solution file of the name ReadersApi.sln under the root directory. Next, I add the existing csproj under the Readers.Api sub directory onto the solution file.


> dotnet sln ReadersApi.sln add Readers.Api/ReadersApi.csproj

This shall add the csproj as well as link the existing API project onto the solution file. Next, I shall add a new Test project under the root directory which shall contain all the unit tests and integration tests I would want to write for the existing ReadersApi project.


> dotnet new xunit --name Readers.Tests

This shall create a sub folder Readers.Tests along with all the test project project under the sub folder. We finish the setup by adding the newly created Test project under the solution we have under the root directory.


> dotnet sln ReadersApi.sln add Readers.Tests/Readers.Tests.csproj

Read: Getting Started with Dotnet Core CLI

Now that we have the things ready to go, we shall add a new UnitTest class file which would contain the Unit Tests onto the UserController existing under the ReadersApi. To keep things simple, I shall write a single unit test for success case when the FetchAllUsers endpoint is invoked. For a UnitTest, a controller is simply yet another plain class with added dependencies to be injected over constructor (if any). And we can test the functionality by simply creating an object of the UserController class.

The UserController class looks as shown below:


namespace ReadersApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        IUnitOfWork repo;

        public UserController(IUnitOfWork repo)
        {
            this.repo = repo;
        }

        [HttpGet]
        [Route("allusers")]
        public IEnumerable<User> GetUsers()
        {
            return repo.UserRepo.Find(x => x.Id != 0);
        }
    }
}

The UserController class has a dependency of type IUnitOfWork and uses a property UserRepo of type IUserRepo from the IUnitOfWork instance. To unit test this, we shall use a mocking unit test case to verify the behaviour of the method GetUsers(). If there are no users available in the system (with a valid Id), then the return list shall be empty, if there are any users found, the result set shall not be empty. We shall verify this functionality using xUnit and Moq, which is an open-source unit testing framework.

Read: Writing Mocking Unit Tests using xUnit and Moq in ASP.NET Core

The Unit Test for the above controller shall be as shown below:


namespace Readers.Tests
{
    public class UserController_Tests
    {
        IUnitOfWork unitOfWork;

        public UserController_Tests()
        {
            //Arrange Moqs
            var repomoq = new Mock<IUserRepo>();
            repomoq.Setup(x => x.Find(It.IsAny<Expression<Func<User, bool>>>())).Returns(new List<User>() { new User() });
            var repo = repomoq.Object;

            var uowmoq = new Mock<IUnitOfWork>();
            uowmoq.Setup(x => x.UserRepo).Returns(repo);
            unitOfWork = uowmoq.Object;
        }

        [Fact]
        public void GetUsers_Success()
        {
            //Arrange
            var userController = new UserController(unitOfWork);

            //Act
            var users = userController.GetUsers().ToList();

            //Assert
            Assert.True(users.Count > 0);
        }
    }
}

We setup a mock alternative for the IUnitOfWork interface and then pass the created mock to the UserController class and then call the GetUsers() method over the controller object. We assert if the result is true or not. This completes the setup of Test project.

And we can test this by running the below command using CLI


> dotnet test

Configuring Jenkins to Capture Test Results:

we can pass additional arguments to the dotnet test command to write the test results onto an xml file, which shall be of the format MSTest. We shall now configure the Jenkins to read data from the generated test results file once the tests are executed and generate a build test stats for us. The command shall be as follows:


> dotnet test --logger:"trx;logFileName=report.xml"

We shall configure the same command under the Jenkins job we created earlier, under a new build step.

data/Admin/2020/1/buildstep.PNG

Observe that we have specified a path %WORKSPACE%/tests/report.xml with an environment variable %WORKSPACE%. It means that the variable is substituted with the current absolute path where the job is being executed. And so the report file shall be generated under the job execution path under a sub directory tests.

Next, we shall add a plugin to the build step which takes care of the test report analysis. Since we are using xunit for test execution, we shall add xUnit plugin to the jenkins server which can then be added to the pipeline.

data/Admin/2020/1/plugins.png

Goto Manage Plugins section under the Jenkins drop menu and search for xUnit under the Available plugins section. Tick the plugin and then click on Install without Restart. This shall install the xUnit plugin for test reporting on Jenkins.

data/Admin/2020/1/addplugin.PNG

Once done, we shall add this plugin as a build step after the test execution build step.

data/Admin/2020/1/addstep.PNG

Once we add the step, we shall select the Report Type as MSTest (since the report generated will be of MSTest format) and then under the pattern, we give the below regular expression


tests/*.xml

By default the plugin searches for any xml report file starting from the %WORKSPACE% path. And since we place all the resultant report files under the test sub folder of the workspace, we give the regex in the similar fashion so that the reports generated under the tests folder shall be taken for report generation.

data/Admin/2020/1/configurestep.PNG

Once this is done, we save the job and let the job run again, we can see that in the build log that the recorder looks for the file and then creates report basing on that.

data/Admin/2020/1/log.PNG

Once this is done, we move back to the job home page, where we can now see a stat graph generated basing on the test results per job run. And when we click on Latest Test Result link (third in the main section), we move to the latest test result page. Clicking on the History in the left gives us the total test stats for all the builds since the test report is configured.

data/Admin/2020/1/teststat1.PNG

data/Admin/2020/1/teststat2.PNG

data/Admin/2020/1/teststat3.PNG

In this way, we can configure test script execution and then record the test reports into stats for the builds in a fully automated fashion using xUnit plugin in Jenkins.

Published 26 days ago

Sponsored Links
We use cookies to improve user experience. Learn More