DEV Community

loading...

Introduction to ASP.NET Core Integration Testing

Kai Oswald
.NET Core + Vue.js = 🔥
Updated on ・2 min read

In this post I'll give you a quick introduction into how you can test your ASP.NET Core Controllers.

Please note that the term "Integration Testing" also covers other cases, such as testing data access or accessing the file system.

Set up the project

A common guideline is to structure your ASP.NET Core projects in the following way:

.
├── src
│   └── MyProject.Api
│       └── Controllers
│           └── ValuesController
└── test
    ├── IntegrationTests
    │   └── MyProject.Api.Test
    │       └── ValuesControllerTest
    └── UnitTests

Install the TestHost NuGet

Create a .NET Core Test project and then install the Microsoft.AspNetCore.TestHost package.
This package will provide options to configure the TestServer.

> Install-Package Microsoft.AspNetCore.TestHost

Create the base class

Create a base class that our ControllerTest classes can inherit from. We will set up the TestServer and HttpClient used to perform requests.

[TestClass]
public abstract class IntegrationTestInitializer
{
    protected HttpClient _client;

    [TestInitialize]
    public void Setup()
    {
        var builder = new WebHostBuilder()
            .UseStartup<Startup>();
        var server = new TestServer(builder);

        _client = server.CreateClient();
    }
}

Create a ControllerTest

Let's pretend the Controller we want to test looks like this

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

With the base class set up, we can then simply inherit from the base class and use our _client to perform requests against the API.

[TestClass]
public class ValuesControllerTest : IntegrationTestInitializer
{
    [TestMethod]
    public async Task CanGetValues()
    {
        List<string> expectedResponse = new List<string> { "value1", "value2" };

        var responseJson = await _client.GetStringAsync("api/values");
        List<string> actualResponse = JsonConvert.DeserializeObject<List<string>>(responseJson);

        Assert.AreEqual(expectedResponse.Count, actualResponse.Count);
        foreach(var expectedValue in expectedResponse)
        {
            Assert.IsTrue(actualResponse.Contains(expectedValue));
        }
    }
}

This post described how you can integration test a very basic ASP.NET Core API.

In the real world you'll probably have a database behind the API that must be accessed and some endpoints may also be protected by an API-Key or JWT.
This post however should only serve as a quick introduction into integration testing.

GitHub logo kai-oswald / IntegrationTestSample

An ASP.NET Core Sample project showcasing how to write integration tests

IntegrationTestSample

An ASP.NET Core Sample project showcasing how to integration test against Controllers

Discussion (10)

Collapse
tomasmuzas profile image
Tomas Mūžas • Edited

Hey, nice post! Just my two cents, but I believe you can use Assert.Equal on collections as well, cleaning up quite a lot of code :)

Collapse
kaos profile image
Kai Oswald Author

It doesn't, but there's a neat utility class for Collections called CollectionAssert which I just found that does that!

So the code could be cut to:

CollectionAssert.AreEqual(expectedResponse, actualResponse);
Collapse
luridsnk profile image
Filippenko Kirill

Good post. But how would you test authorized endpoints?

Collapse
kaos profile image
Kai Oswald Author

This depends on the authorization methods used to protect those endpoints.

For example if you use JWT you could generate your token in the TestInitialize and set the Authorization header on the client.

I'm planning on doing another post going into more detail.

Collapse
luridsnk profile image
Filippenko Kirill • Edited

Good point.
But if you're ought to create and API for SPA, you'd probably consider not only 'header' implementation.
For those reasons I personally prefer to send JWT in HttpOnly cookie. Could you please cover this case as well?

Thread Thread
kaos profile image
Kai Oswald Author
Collapse
sakinala1 profile image
sakinala1 • Edited

nice post..thanks for the knowledge sharing...hey can you give examples with passing parameters..please and if possible can you please explain briefly more about this topic

Collapse
kaos profile image
Kai Oswald Author

I didn' want to cover this, because these are general Testing basics.
But to pass parameters to your tests you can use the DataRow attribute.

This maps the values in your Datarows to the test method params.

[DataRow(1)]
[DataRow(2)]
void Test(int id) 
{

}
Collapse
sakinala1 profile image
sakinala1

iam using webapplicationfactory

calling methods as
var response = await _client.GetStringAsync("api/controller/method");

here how to pass parameters...to that method..hope you understand

Thread Thread
kaos profile image
Kai Oswald Author

You can just use string interpolation.

var url = $"api/controller/method/{id}?param1={param1}&param2={param2}";
var response = await _client.GetStringAsync(url);