In this application, we are using JUST.net with custom functions. Custom functions in JUST.net must be static methods. I created a class that defines all static functions; these functions are registered to the JUST.net context via reflection. I need to include logging in these static functions in case one of the mappings fails.
To accomplish this, we have code like this:
public class Transformations
{
private static ILogger<Transformation> _logger;
public Transformations(ILogger<Transformations> logger)
{
_logger = logger;
}
public static string MapAddress(string? streetNumber, string? streetName)
{
if(string.IsNullOrEmpty(streetNumber)
{
_logger.LogError("The property was not provided.");
}
// etc...
}
// etc...
}
When I call it from my tests, the logger works if I instantiate the class and reference the functions statically. If I do not instantiate the class and reference the methods statically, the logger does not work.
I.e.:
public class AddressUnitTest
{
private readonly Transformations _transformations;
public AddressUnitTest()
{
var serilog = new LoggerConfiguration().WriteTo.Console().CreateLogger();
var loggerFactory = new LoggerFactory().AddSerilog(serilog);
var logger = loggerFactory.CreateLogger<Transformations>();
_transformations = new Transformations(logger);
}
[Fact]
public void Address(string? streetNumber, string? streetName)
{
var actualValue = Transformations.MapAddress(streetNumber, streetName);
// etc...
}
}
Given you cannot use _transformations.MapAddress()
and must reference the methods statically, i.e.: Transformation.MapAddress()
, why does the logger work when I instantiate a seemingly unrelated version of it?
That is, why does setting _transformations = new Transformations(logger);
give Transformations.MapAddress()
access to the logger?
It seems to work; I just don't understand why. Is there a better way to accomplish this?
The reason for this is that the only time that the _logger
field is initialised to anything is in the class constructor.
It would be better to write a static method to initialise the logger, and make your entire class static (so that all its members must be static) so that this confusion doesn't arise:
public static class Transformations
{
private static ILogger<Transformation> _logger;
public static void InitialiseLogger(ILogger<Transformations> logger)
{
_logger = logger;
}
public static string MapAddress(string? streetNumber, string? streetName)
{
if(string.IsNullOrEmpty(streetNumber)
{
_logger.LogError("The property was not provided.");
}
// etc...
}
// etc...
}
In your unit tests, it should be possible to have a startup method which calls Transformations.InitialiseLogger()
just once for all the unit tests, so you don't have to repeat it in each test method. (Or some other way - I'm not familiar with how xUnit does this.)