Tag Archives: unit tests

Unit tests in Entity Framework Core 5

Tests are an integral part of software development. These are separate programs that allow you to check if a piece of the program written by us does exactly what it should. Unit tests are small pieces of code that test individual program elements and in Entity Framework Core 5 it’s surprisingly easy to write them.

In memory or not

Microsoft recommends that when writing tests that use EF Core, you should use a real database whenever possible. In fact, it is best to use the database in exactly the same configuration and on the same server on which our application is to run. This approach may not make sense when it comes to cost, as Microsoft also admits. Performance tests should certainly check our solutions in an environment as close to production as possible. However, when writing unit tests, it’s enough to keep the database in memory. Entity Framework Core allows you to run on a virtual database created only in memory. We can also use the SQLite database because it works fast and does not need a server. It also has a mode in which it can run in memory. In this chapter, we won’t go into detail about using SQLite for testing, but I can assure you that it doesn’t take much effort.

Writing unit tests

In Entity Framework Core 5 it’s very easy to configure the database to run in memory. In a test project, just install the NuGet package called Microsoft.EntityFrameworkCore.InMemory, but also a few more might come in handy. Let’s check the full list:

  • Microsoft.EntityFrameworkCore.InMemory – to run EF Core 5 in memory
  • NUnit – a framework to write and run unit tests
  • NUnit3TestAdapter – an adapter to run NUnit tests in Visual Studio
  • FluentAssertions – easy library to write nice and readable assertions

For testing, I will use the ReservationController class. Here is its full content:

[ApiController]
[Route("[controller]")]
public class ReservationsController : ControllerBase
{
    private readonly PrimeDbContext primeDbContext;

    public ReservationsController(PrimeDbContext _primeDbContext)
    {
        primeDbContext = _primeDbContext;
    }

    [HttpGet]
    public async Task<IEnumerable<Reservation>> Get()
    {
        return await primeDbContext.Reservations.Include(r => r.Room).AsNoTracking().ToListAsync();
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetById(int id)
    {
        var reservation = await primeDbContext.Reservations.FindAsync(id);
        if (reservation == null)
        {
            return NotFound();
        }

        await primeDbContext.Entry(reservation).Collection(r => r.Profiles).LoadAsync();
        await primeDbContext.Entry(reservation).Reference(r => r.Room).LoadAsync();

        return Ok(reservation);
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] NewReservation newReservation)
    {
        var room = await primeDbContext.Rooms.FirstOrDefaultAsync(r => r.Id == newReservation.RoomId);
        var guests = await primeDbContext.Profiles.Where(p => newReservation.GuestIds.Contains(p.Id)).ToListAsync();

        if (room == null || guests.Count != newReservation.GuestIds.Count)
        {
            return NotFound();
        }

        var reservation = new Reservation
        {
            Created = DateTime.UtcNow,
            From = newReservation.From.Value,
            To = newReservation.To.Value,
            Room = room,
            Profiles = guests
        };

        var createdReservation = await primeDbContext.Reservations.AddAsync(reservation);
        await primeDbContext.SaveChangesAsync();

        return Ok(createdReservation.Entity.Id);
    }
}

I named the test class ReservationControllerTests, which is the name of the class and the Tests ending at the end. In these tests, I will focus on checking how to replace data in Entity Framework Core, and not to test all possible cases.

The basis here is the appropriate preparation of PrimeDbContext for testing. The very base of the class with tests looks like this:

public class ReservationsControllerTests
{
    private DbContextOptions<PrimeDbContext> dbContextOptions = new DbContextOptionsBuilder<PrimeDbContext>()
        .UseInMemoryDatabase(databaseName: "PrimeDb")
        .Options;
    private ReservationsController controller;

    [OneTimeSetUp]
    public void Setup()
    {
        SeedDb();

        controller = new ReservationsController(new PrimeDbContext(dbContextOptions));
    }

    private void SeedDb()
    {
        using var context = new PrimeDbContext(dbContextOptions);
        var rooms = new List<Room>
        {
            new Room { Id = 1, Description = "Room nr 1", Number = 1, Level = 1, RoomType = RoomType.Standard },
            new Room { Id = 2, Description = "Room nr 2", Number = 2, Level = 1, RoomType = RoomType.Standard },
            new Room { Id = 3, Description = "Room nr 3", Number = 3, Level = 2, RoomType = RoomType.Suite }
        };

        var profiles = new List<Profile>
        {
            new Profile { Id = 1, Ref = "Profile 1", Forename = "Michał", Surname = "Białecki" },
            new Profile { Id = 2, Ref = "Profile 2", Forename = "John", Surname = "Show" },
            new Profile { Id = 3, Ref = "Profile 3", Forename = "Daenerys", Surname = "Targaryen" }
        };

        context.AddRange(rooms);
        context.AddRange(profiles);

        context.AddRange(new List<Reservation>
        {
            new Reservation
            { 
                Id = 1,
                Room = rooms[0],
                Profiles = new List<Profile>{ profiles[0] },
                From = DateTime.Today,
                To = DateTime.Today.AddDays(2)
            },
            new Reservation
            {
                Id = 2,
                Room = rooms[2],
                Profiles = new List<Profile>{ profiles[1], profiles[2] },
                From = DateTime.Today.AddDays(1),
                To = DateTime.Today.AddDays(3)
            }
        });

        context.SaveChanges();
    }
}

The first thing that immediately catches our attention is the SeedDb method, which is used to add test data to the EF Core context. For these tests, the data will be entered only once, at the very beginning thanks to the [OneTimeSetUp] attribute. The state of the database will be preserved as long as the process that performs these tests is running. However, the more important part is at the top, which is creating a dbContextOptions. Note that this is where we use the UseInMemoryDatabase option, and then create the PrimeDbContext class using this object. When creating, we give the name of the database and always use the same one. Another very important line is:

using var context = new PrimeDbContext(dbContextOptions);

At first, we use the using keyword because we don’t want Garbage Collector to remove the context variable from memory while the test is running.

Since we already have a configured database and data, it’s time to test:

[Test]
public async Task Get_FetchesReservationsWithoutRoomsAndGuests()
{
    using var context = new PrimeDbContext(dbContextOptions);
    var reservations = (await controller.Get()).ToList();

    reservations.Count.Should().Be(2);
    reservations.All(r => r.Room == null).Should().BeFalse();
    reservations.All(r => r.Profiles == null).Should().BeTrue();
}

In the first test, we get all reservations and check if their dependencies are loaded. In this case, it won’t, because the Get method in the controller doesn’t force dependencies to be loaded. Let’s check another method.

[Test]
public async Task GetById_WhenIdIsProvided_FetchesReservationWithRoomsAndGuests()
{
    using var context = new PrimeDbContext(dbContextOptions);
    var result = await controller.GetById(2);
    var okResult = result.As<OkObjectResult>();
    var reservation = okResult.Value.As<Reservation>();

    reservation.Should().NotBeNull();
    reservation.Profiles.Should().NotBeNull();
    reservation.Room.Should().NotBeNull();
}

In the second test, we take a single booking and here we check that both the room and the profiles are loaded. This is because in the GetById method we use the Collection and Reference methods to load these dependencies. Now let’s test the Post method.

[Test]
public async Task Post_WithRoomAndProfiles_AddsReservation()
{
    var newReservation = new NewReservation
    {
        From = DateTime.Today.AddDays(3),
        To = DateTime.Today.AddDays(7),
        RoomId = 3,
        GuestIds = new List<int> { 2 }
    };

    using var context = new PrimeDbContext(dbContextOptions);
    var result = await controller.Post(newReservation);

    var okResult = result.As<OkObjectResult>();
    var reservationId = okResult.Value.As<int>();
    var addedReservation = await context.Reservations
        .Include(p => p.Profiles)
        .Include(r => r.Room)
        .FirstOrDefaultAsync(r => r.Id == reservationId);

    addedReservation.Should().NotBeNull();
    addedReservation.Profiles.Should().NotBeNull();
    addedReservation.Profiles.Count.Should().Be(1);
    addedReservation.Profiles[0].Id.Should().Be(2);
    addedReservation.Room.Should().NotBeNull();
    addedReservation.Room.Id.Should().Be(3);
}

The last test checks if the added reservation was added correctly. We check whether the room and the guest’s profile have been properly assigned to the new booking.

The summary

Unit testing in Entity Framework Core is really simple and understandable. Only a few lines of configuration allow us to use the dbContext class to prepare the desired database state. We do not have to replace individual collections in PrimeDbContext separately, as was the case with the Entity Framework tests. In this respect, Entity Framework Core is refined, and unit testing using it does not differ significantly from any other unit tests. Working with them is easy and fun, which is exactly as it should be.

All code mentioned here is available on my GitHub, feel free to take a look at how EF Core can be used in other parts of the project.

Thanks for reading! 😊

Perfect console application in .net Core: add unit tests

Unit test are crucial part in software development process. In late 1990s Kent Beck stated that writing tests is the most important part of writing software in ExtremeProgramming metodology. You can read a bit more about it in Martins Fowler article.

This is a part of a series of articles about writing a perfect console application in .net core 2. Feel free to read more:

My example

To have a simple example how to add tests to .net core console application I created a TicketStore app. It is a console app to reserve tickets in cinema. It’s structure looks like this:

Here is how command handling looks like:

    command = Console.ReadLine();
    if (!_commandValidator.IsValid(command))
    {
        Console.WriteLine($"Sorry, command: '{command}' not recognized.");
    }

And CommandValidator looks like this:

As you noticed validator contains regular expression and parsing logic, that can always be faulty. We only allow a column to be from A to H and seat to be between 1 and 15. Let’s add unit test to be sure that it works that way.

Adding tests project

Adding a test project

Project name that I would like to test is MichalBialecki.com.TicketStore.Console so I need to add a class library with name
MichalBialecki.com.TicketStore.Console.Tests.

Adding unit tests packages

To write unit tests I’m adding my favourite packages:

  • NUnit – unit test framework
  • NUnit3TestAdapter – package to run tests
  • NSubstitute – mocking framework
  • Microsoft.NET.Test.Sdk – it’s important to remember about this one, tests would not run without it

Now we can start writing tests.

First test

I added a CommandValidatorTests and now my project structure looks like this:

And test looks like this.

    using MichalBialecki.com.TicketStore.Console.Helpers;
    using NUnit.Framework;

    [TestFixture]
    public class CommandValidatorTests
    {
        private CommandValidator _commandValidator;

        [SetUp]
        public void SetUp()
        {
            _commandValidator = new CommandValidator();
        }

        [TestCase("A1", true)]
        [TestCase("A15", true)]
        [TestCase("A11", true)]
        [TestCase("H15", true)]
        [TestCase("H16", false)]
        [TestCase("K15", false)]
        [TestCase("I4", false)]
        [TestCase("K.", false)]
        [TestCase("", false)]
        [TestCase(null, false)]
        public void IsValid_GivenCommand_ReturnsExpectedResult(string command, bool expectedResult)
        {
            // Arrange & Act
            var result = _commandValidator.IsValid(command);

            // Assert
            Assert.AreEqual(expectedResult, result);
        }
    }

In Resharper unit tests sessions window all tests passed.

Notice how test results are shown – everything is clear from the first sight. You can immidiately see what method is tested and with what conditions.

If you’re interested what are the best practices to write unit tests, have a look at my article: https://www.michalbialecki.com/2019/01/03/writing-unit-tests-with-nunit-and-nsubstitute/. It will guide you through the whole process and clearly explaining best practices.

  All code posted here you can find on my GitHub: https://github.com/mikuam/console-app-net-core

 

Writing unit tests with NUnit and NSubstitute

Imagine you are a Junior .Net Developer and you just started your development career. You got your first job and you are given a task – write unit tests!

Nothing to worry about, since you got me. I’ll show you how things are done and what are the best practices to follow.

Introduction

Writing unit tests is crucial to develop high-quality software and maintain it according to business requirements. Tests are the tool for developer to quickly check a small portion of code and ensure that it does what it should. In many cases tests can be unnecessary, requiring maintenance, without any gained value. However, writing tests is a standard and art that every developer should master.

Note, that writing unit tests is easy only when the code to test is written in a correct way. When methods are short, do a single thing and don’t have many dependencies, they are easy to test.

To write unit tests in this post I’ll use NUnit and NSubstitute. Those are two very popular nuget packages, that you can easily find. All code will be written in .Net Core.

Following the AAA pattern

The AAA (Arrange, Act, Assert) unit test writing pattern divides every test into 3 parts:

  • Arrange – in this part, you prepare data and mocks for a test scenario
  • Act – executing a single action that we want to test
  • Assert – checking whether expectations are met and mocks were triggered

Let’s have a look at a simple code, that we will test:

    public class ProductNameProvider : IProductNameProvider
    {
        public string GetProductName(string id)
        {
            return "Product " + id;
        }
    }

And a simple test would look like this:

    [TestFixture]
    public class ProductNameProviderTests
    {
        [Test]
        public void GetProductName_GivenProductId_ReturnsProductName()
        {
            // Arrange
            var productId = "1";
            var productNameProvider = new ProductNameProvider();

            // Act
            var result = productNameProvider.GetProductName(productId);

            // Assert
            Assert.AreEqual("Product " + productId, result);
        }
    }

This is a simple test, that checks whether the result is correct. There is a TestFixture attribute, that indicates, that this class contains a group of tests. a Test attribute marks a single test scenario.

  • in Arrange part we prepare productNameProvider and parameters
  • in Act there is only a single line where we execute GetProductName, which is a testing method
  • in Assert we use Assert.AreEqual to check the result. Every test needs to have at least one assertion. If any of the assertions fails, the whole test will fail

Test edge-cases

What you could see in an example above is a happy-path test. It tests only an obvious scenario. You should test code when a given parameter is not quite what you expect. The idea of that kind of tests is perfectly described in this tweet:

Let’s see an example with a REST API controller method. First, let’s see code that we would test:

    [Route("api/[controller]")]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        private readonly IProductService _productService;
        private readonly ILogger _logger;

        public ProductsController(IProductService productService, ILoggerFactory loggerFactory)
        {
            _productService = productService;
            _logger = loggerFactory.CreateLogger(nameof(ProductsController));
        }

        [HttpPost]
        public string Post([FromBody] ProductDto product)
        {
            _logger.Log(LogLevel.Information, $"Adding a products with an id {product.ProductId}");

            var productGuid = _productService.SaveProduct(product);

            return productGuid;
        }
    }

This is a standard Post method, that adds a product. There are some edge-cases though, that we should test, but first let’s see how happy-path test would look like.

    [TestFixture]
    public class ProductsControllerTests
    {
        private IProductService _productService;
        private ILogger _logger;

        private ProductsController _productsController;

        [SetUp]
        public void SetUp()
        {
            _productService = Substitute.For<IProductService>();
            _logger = Substitute.For<ILogger>();
            var loggerFactory = Substitute.For<ILoggerFactory>();
            loggerFactory.CreateLogger(Arg.Any<string>()).Returns(_logger);

            _productsController = new ProductsController(_productService, loggerFactory);
        }

        [Test]
        public void Post_GivenCorrectProduct_ReturnsProductGuid()
        {
            // Arrange
            var guid = "af95003e-b31c-4904-bfe8-c315c1d2b805";
            var product = new ProductDto { ProductId = "1", ProductName = "Oven", QuantityAvailable = 3 };
            _productService.SaveProduct(product).Returns(guid);

            // Act
            var result = _productsController.Post(product);

            // Assert
            Assert.AreEqual(result, guid);
            _productService.Received(1).SaveProduct(product);
            _logger
                .Received(1)
                .Log(LogLevel.Information, 0, Arg.Is<FormattedLogValues>(v => v.First().Value.ToString().Contains(product.ProductId)), Arg.Any<Exception>(), Arg.Any<Func<object, Exception, string>>());
        }
    }

Notice  that I added:

[SetUp]
public void SetUp()

SetUp method will be run before every test and can contain code that we would need to execute for every test. In my case, it is creating mocks and setting up some mocks as well. For example, I set up a logger in order to be able to test it later. I also specify, that my ILogger mock will be returned whenever I create a logger.

loggerFactory.CreateLogger(Arg.Any<string>()).Returns(_logger);

I could do that in Arrange part of the test, but I would need to do it for every test. In Arrange I set up a _productService mock that returns guid:

_productService.SaveProduct(product).Returns(guid);

And later in Assert, I check, that this method was in fact called. I also check the result of an Acting part.

Assert.AreEqual(result, guid);
_productService.Received(1).SaveProduct(product);

Now, let’s see how we can test an edge case, when a developer using this API, will not provide a value.

    [Test]
    public void Post_GivenNullProduct_ThrowsNullReferenceException()
    {
        // Act &  Assert
        Assert.Throws<NullReferenceException>(() => _productsController.Post(null));
    }

In one line we both act and assert. We can also check exception fields in next checks:

    [Test]
    public void Post_GivenNullProduct_ThrowsNullReferenceExceptionWithMessage()
    {
        // Act &  Assert
        var exception = Assert.Throws<NullReferenceException>(() => _productsController.Post(null));
        Assert.AreEqual("Object reference not set to an instance of an object.", exception.Message);
    }

The important part is to set Returns values for mocks in Arrange and check mocks in Assert with Received.

Test Driven Development

To be fair with you I need to admit that this controller method ist’s written in the best way. It should be async, have parameters validation and try-catch block. We could turn our process around a bit and write tests first, that would ensure how the method should behave. This concept is called Test Driven Development – TDD. It requires from developer to write tests first and sets acceptance criteria for code that needs to be implemented.

This isn’t the easiest approach. It also expects that we know all interfaces and contracts in advance. In my opinion, it’s not useful in real-life work, maybe with one exception. The only scenario I’d like to have tests first would be a refactoring of an old code, where we write one part of it anew. In this scenario, I would copy or write tests to ensure that new code works exactly the same as the old one.

Naming things

Important thing is to follow patterns that are visible in your project and stick to it. Naming things correctly might sound obvious and silly, but it’s crucial for code organization and it’s visibility.

 

 

 

First, let’s have a look at the project structure. Notice that all test projects are in Tests directory and names of those projects are same as projects they test plus “Tests”. Directories that tests are in are corresponding to those that we test, so that directory structure in both projects is the same. Test classes names are also the same.

 

 

 

 

 

Next thing is naming test scenarios. Have a look test results in Resharper window:

In this project, every class has its corresponding test class. Each test scenario is named in such pattern: [method name]_[input]_[expected result]. Only looking at the test structure I already know what method is tested and what this test scenario is about. Remember that the test scenario should be small and should test a separate thing if that’s possible. It doesn’t mean that when you test a mapper, you should have a separate scenario for every property mapped, but you might consider dividing those tests to have: happy-path test and all the edge cases.

 

That’s it! You are ready for work, so go and write your own tests:)

 

 All code posted here you can find on my GitHub: https://github.com/mikuam/unit-testing-examples

You can play with a code a bit, write more classes and tests. If you like this topic or you’d like to have some practical test assignment prepared to test yourself, please let me know:)