- Monday Labs
- Posts
- Scaffolding Unit Tests in ASP.NET Core
Scaffolding Unit Tests in ASP.NET Core
In this post, I will demonstrate how to scaffold a unit test (automated testing) in ASP.NET Core MVC using xUnit
Testing is a central part of software development. It can provide you with confidence that your application behaves as desired. This process can also detect errors before your application reaches production. You can perform manual testing or automated testing for your project, but I definitely prefer automated testing. There are many types of automated testing in software development, one of which is unit testing.
A unit test is a software development process that involves testing individual units or components of a software application. It should test a specific behavior within the production code.
In this post, I will demonstrate how to scaffold a unit test (automated testing) in ASP.NET Core MVC using xUnit. First, we will create a new ASP.NET Core MVC project. This project is about creating a simple Hogwarts House Sorting app, similar to the Sorting Hat in the Harry Potter series. The main feature of this app is that users can receive their house assignment after they submit their name.
Create Projects
Let’s open PowerShell (or Terminal if you’re using Linux or macOS) and create a folder named ‘hogwarts-house-web-app’, then change into that folder.
New-Item -Path "hogwarts-house-web-app" -ItemType Directory; cd "hogwarts-house-web-app"
Next, create two projects, HouseSorting for our app and HouseSorting.Tests for testing. Use this command to create the HouseSorting project.
dotnet new mvc -o HouseSorting
Use the following command to create HouseSorting.Tests.
dotnet new xunit -o HouseSorting.Tests
After that, let’s put all the projects in a solution using this command. This command creates a .sln file in the current folder, with the same name as the folder.
dotnet new sln
Add the HouseSorting and HouseSorting.Tests projects to the solution file by running the following command.
dotnet sln add .\HouseSorting\HouseSorting.csproj
For HouseSorting.Tests, use this command.
dotnet sln add .\HouseSorting.Tests\HouseSorting.Tests.csproj
Next, add the HouseSorting as a dependency to the HouseSorting.Tests project.
dotnet add .\HouseSorting.Tests\HouseSorting.Tests.csproj reference .\HouseSorting\HouseSorting.csproj
This is the folder structure of this solution right now.
hogwarts-house-web-app/
├── hogwarts-house-web-app.sln
├── HouseSorting
└── HouseSorting.Tests
Open “hogwarts-house-web-app” folder in VS Code (or your favorite IDE).
Let’s create SortingController inside HouseSorting\Controllers
folder to handle name submission from user and return house information to user.
Update SortingController with the following code.
using Microsoft.AspNetCore.Mvc;
namespace HouseSorting.Controllers;
public class SortingController : Controller
{
public IActionResult Index(string name)
{
if (!ModelState.IsValid || String.IsNullOrEmpty(name))
{
return BadRequest(ModelState);
}
string[] houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"];
Random random = new();
var randomIndex = random.Next(houses.Length);
ViewData["house"] = houses[randomIndex];
ViewData["name"] = name;
return View();
}
}
SortingController has one method, Index method. This method receives string type name parameter. SortingController returns BadRequest
when the model state is invalid and name parameter is empty string or null. Variable house contains all houses in Hogwarts. We use Random class to generate house assignment for user.
Next, create Sorting folder inside HouseSorting\Views
and create Index.cshtml
inside this new folder for Index Method.
Copy and paste this code to HouseSorting\Views\Sorting\Index.cshtml.
@{
ViewData["Title"] = "House Sorting Page";
}
<h1>@ViewData["Title"]</h1>
<p>Hello @ViewData["name"]! Your house is @ViewData["house"].</p>
From “hogwarts-house-web-app” folder, Let’s run our web app via powershell.
dotnet run --project .\HouseSorting\
If you visit /sorting route, you will see a bad request information. We need to provide name parameter for this route. You can use parameter in url like /sorting?name=Harry to see the house assigment result. Use Ctrl + C to stop our web app.
Create Tests
Before we create tests for hogwarts-house-web-app, delete default test file .\HouseSorting.Tests\UnitTest1.cs
. Then, create a SortingControllerTests.cs file inside .\HouseSorting.Tests
to test SortingController. Add the following code to SortingControllerTests.cs.
using HouseSorting.Controllers;
using Microsoft.AspNetCore.Mvc;
namespace HouseSorting.Tests;
public class SortingControllerTests
{
[Fact]
public void Index_ReturnsAViewResult_WithHouseInformation()
{
var controller = new SortingController();
var result = controller.Index("Jorge Potter") as ViewResult;
string[] houses = ["Gryffindor", "Hufflepuff", "Ravenclaw", "Slytherin"];
var house = result!.ViewData["house"] as string;
Assert.IsType<ViewResult>(result);
Assert.Contains(house, houses);
}
[Fact]
public void IndexPost_ReturnsBadRequestResult_WhenModelStateIsInvalid()
{
var controller = new SortingController();
var result = controller.Index(String.Empty);
var badRequestResult = Assert.IsType<BadRequestObjectResult>(result);
Assert.IsType<SerializableError>(badRequestResult.Value);
}
}
The SortingControllerTests class contains two test methods. The Index_ReturnsAViewResult_WithHouseInformation method tests the result of the Index method on SortingController. It asserts that SortingController returns a view and that the view contains ViewData about house assignment.
The IndexPost_ReturnsBadRequestResult_WhenModelStateIsInvalid method tests the response when the Model State is invalid, or when the name parameter in the Index method is null or an empty string.
The [Fact] attribute declares a test method that’s run by the test runner.
From the “hogwarts-house-web-app” folder, run this command via powershell.
dotnet test
The dotnet test command builds both projects and runs the tests. You will see that all tests passed.
...
Starting test execution, please wait...
A total of 1 test files matched the specified pattern.
Passed! - Failed: 0, Passed: 2, Skipped: 0, Total: 2, Duration: 6 ms - HouseSorting.Tests.dll (net8.0)
In this post, you will learn how to scaffold unit tests in an ASP.NET Core project and gain some insight into what unit testing in ASP.NET Core should look like. You can use this structure for your project and add testing to make your application more reliable and maintainable.
Here is my repository about this post.
Finally, I believe this could be your mantra for testing: ‘Code, Test, Relax.’