Articles Have Less Production Issues with the Help of xUnit (.NET Core project) by Daan Acohen

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Have Less Production Issues with the Help of xUnit
Daan Acohen - 24/May/2020
[SHOWTOGROUPS=4,20]
By using xUnit the right way, your logging can be improved and production problems can be solved easily or even prevented.

Considering the way many tests with xUnit are written, two things need to be improved: the tests need to be more realistic and should prevent having limited logging.

Making tests more realistic will make production problems less likely, Moreover, testing what has been logged prevents the problem of having to limited logging details to solve a production issue once it occurs. This article explains how to prevent such problems in your xUnit tests.

Introduction
Production issues are a well-known problem. In most cases, you do not know what could have caused the problem so reading the logs is the first thing to do. After reading the logs, the following questions are likely to be asked within the development team:
  1. Why isn't the object logged we expect to be logged?
  2. Why can't we find a warning or error message that describes the problem?
  3. Why can't we find the exception that must have occurred?
  4. Why didn't our tests fail since there is clearly something wrong?
From a TDD perspective, two improvements are needed:
  1. The automated tests need to become more realistic to reproduce real problems.
  2. Tests need to fail on absence of logging.
This article explains how to do that.

Background
It will be really helpful if you have ever worked with xUnit before since the test examples are based on that. In addition, some experience with .NET Core is helpful too since that is the technology we use here.

Using the code
For demonstration purposes, we use a really simple controller method. The incoming value contains the FirstName, MiddleName and LastName to return the full name as an ActionResult.
Код:
[HttpPut]
public ActionResult<string> Put([FromBody] Name value)
{
_logger.LogWarning("Warning Logged");
_logger.LogInformation("This is the input {name}", value);
_logger.LogError(new InvalidDataException("Some exception message"),"Some Exception");

return Ok($"{value.FirstName} {value.MiddleName} {value.LastName}");
}

For this method, we need a test that can detect what is logged: an InvalidDataException, some logging messages and a data object of the type Name. Moreover, the test needs to be realistic which means that it knows and uses the Startup class where the dependencies are set. In regular unit tests, this is not the case but in integration tests for .NET Core, this is the case as becomes clear from the code shown here:
Код:
[Fact]
public async Task NoMiddleNamePutTest()
{
await using (var fixture = new Fixture<Startup>())
{
var controller = fixture.Create<LogicController>();
var response = controller.Put(new Name()
{
FirstName = "F",
LastName = "L"
});
Assert.Equal(200, ((ObjectResult)response.Result).StatusCode);
Assert.Single(fixture.LogSource.GetWarnings());
var dataLogged = fixture.LogSource.GetLoggedObjects<Name>().ToList();
Assert.Single(dataLogged);
Assert.Equal("F", dataLogged.Single().Value.FirstName);
Assert.Contains(fixture.LogSource.GetLogLines(), a => a == "Warning Logged");
Assert.Contains(fixture.LogSource.GetLogLines(), a => a.Contains("This is the input"));
Assert.Single(fixture.LogSource.GetExceptions().OfType<InvalidDataException>());
}
}

The Fixture<> class comes from Для просмотра ссылки Войди или Зарегистрируйся

It uses the WebApplicationFactory<> class (explained Для просмотра ссылки Войди или Зарегистрируйся) to reduce the boilerplate code to be written by the developer.

Real class dependencies set in the Startup class (not mocks) are used to make the tests realistic.

The LogSource property enables the developer to call methods that return the data we care about (like logged data objects, logged lines and logged exceptions).

Production problems are becoming less likely since real dependencies are used so those issues are likely to be covered in the tests.

Moreover, if there are production problems, there will be enough logging available to help you resolving the problems since the xUnit tests will simply fail and prevent deployment if there is not enough logging,

The code is available on Для просмотра ссылки Войди или Зарегистрируйся..

Points of Interest
While writing the code, I started realising more how important automated tests are. As developers, we need to write integration tests for CI purposes, not just unit tests. Moreover, we should not only focus on the required functionality but also on the logging. Having good logging is essential for quickly resolving production issues and with the Для просмотра ссылки Войди или Зарегистрируйся, we can easily detect what has been logged.

History
  • 24th May, 2020: Initial version

License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

[/SHOWTOGROUPS]