Entity Framework Core 2 Unit Testing in .NET Core 2

Full source code available here.

Unit testing Entity Framework used to be quite a chore, but over the past few years it has become significantly easier.

In this post I’m going to show you how to use the InMemory database with named instances.

The ProductsController is fairly standard, it takes a DbContext in the constructor which is instantiated by dependency injection (see the Startup.cs in the source code if you don’t know how to do this).

public ProductsController(ProductsContext context)
{
    _productsContext = context;
}

The action methods use the context to query the database and return responses to the callers. From the response status code the caller knows if there is also content (products) in the response.

[HttpGet]
public async Task<IActionResult> Get()
{
    var products = await _productsContext.Products.ToListAsync();

    if (!products.Any())
    {
        return NotFound();
    }
    return Ok(products);
}

Testing
In the unit test project, (see here if you need help creating this), I’ve added a ProductsControllerTests class.

In my Get test I created an instance of a DbContextOptions by using the DbContextOptionsBuilder. On the builder I specify that I want an InMemoryDatabase and give it a unique name for this test – this is important, if the name is not unique across all tests or if it is left blank you will end up with a database shared by more than one test.

In the Arrange portion of the test I also instantiate the ProductsContext; then instantiate a few products, add them to the context; don’t forget to save the changes; finally create an instance of the of ProductsController.

Here is the full Arrange portion of the test.

// Arrange
var options = new DbContextOptionsBuilder<ProductsContext>()
.UseInMemoryDatabase(databaseName: "Get test")
.Options;

ProductsContext productsContext = new ProductsContext(options);
Product product01 = new Product { Name = "first", ProductId = 1, Sku = "abc" };
Product product02 = new Product { Name = "second", ProductId = 2, Sku = "def" };

productsContext.Products.Add(product01);
productsContext.Products.Add(product02);
await productsContext.SaveChangesAsync();
ProductsController controller = new ProductsController(productsContext);

Next I Act, just calling the controller’s Get method. The controller already has the context and the get method will query it just like a real database.

// Act
var actionResult = await controller.Get();

Then I Assert. 

// Assert
var okObjectResult = actionResult as OkObjectResult;

List<Product> products = okObjectResult.Value as List<Product>;

Assert.Equal(2, products.Count());

Note the as OkObjectResult type, I know it's that type because that is what I return from the ProductsController.

I assign the value of the okObjectResult to a List.Assert that there are two entries in the list.

Testing NotFound - 404
In the ProductsController I also have a Get that takes a productId as an int and returns a product.
You should also test the scenario that no entries in the database match the search. In this case I am returning a NotFound, you may choose to return something else like an OK with nothing in it. In the case of a list, some people like to return an empty list; there is much debate on this topic and I have no interest in adding my two cents.

To test the NotFound response, the Act and Assert change a little. I call the GET method with an id that I know will return nothing.

// Act
var actionResult = await controller.Get(999);

// Assert
var notFoundResult = actionResult as NotFoundResult;

Assert.Equal(404, notFoundResult.StatusCode);

Full source code available here.

Unit Testing .NET Core 2 Web Api

Full source code available here.

Unit testing Web API controllers in .NET Core 2 is very easy.

I have very simple GET and POST methods.

[Route("api/[controller]")]
public class ValuesController : Controller
{
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        // imagine some db logic
        List<string> values = new List<string>() { "value1", "value2" };
        return Ok(values);
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody]string value)
    {
        // imagine some db logic
        return Created("", value);
    }
}

Add an xUnit Test Project to your solution.

In the test project add a ValuesControllerTests class.

Add a method to test the ValuesController.Get like this –

[Fact]
public async Task TestGet()
{
    // Arrange
    var controller = new ValuesController();

    // Act
    IActionResult actionResult = await controller.Get();

    // Assert
    Assert.NotNull(actionResult);

    OkObjectResult result = actionResult as OkObjectResult;

    Assert.NotNull(result);

    List<string> messages = result.Value as List<string>;

    Assert.Equal(2, messages.Count);
    Assert.Equal("value1", messages[0]);
    Assert.Equal("value2", messages[1]);
}

Note here how I expect the result to be an OkObjectResult

OkObjectResult result = actionResult as OkObjectResult;

And here where I cast the result.Value as List, the type I sent from the controller. No deserializing from json, strings or byte arrays needed!

List<string> messages = result.Value as List<string>;

Now it is simple to perform the appropriate asserts.

Here is another example, this time testing the ValuesController.Post().

[Fact]
public async Task TestPost()
{
    // Arrange
    var controller = new ValuesController();

    // Act
    IActionResult actionResult = await controller.Post("Some value");

    // Assert
    Assert.NotNull(actionResult);
    CreatedResult result = actionResult as CreatedResult;

    Assert.NotNull(result);
    Assert.Equal(201, result.StatusCode);
} 

You can also test a result for NotFoundResult, OkResult, UnauthorizedResult, etc.

Full source code available here.