Unit Tests in .Net Core

Image by testbytes from Pixabay

There are many tools to write unit tests. here is what I like to use:

FakeItEasy for mocks

I really prefer FakeItEasy over Moq and others for two reasons. The first reason is that a mock is a real object and it does not require .Object everywhere. The 2nd reason the clean and easy setup and verification.

I prefer this code:

A.CallTo(() => service.Setup.SendAsync(A<int>._)).Returns(3);

over:

service.Setup(x => x.SendAsync(It.IsAny<int>())).ReturnsAsync(3);

Shouldly for asserts

I really prefer Shouldly because typical Assert is just plain ugly. it might be a personnel preference, but I just like that code

cart.Status.ShouldBe(status);
count.ShouldBe(200);

over:

Assert.Equal(cart.Status, status);
Assert.Equal(count, 200);

AutoFixture for stubbing

The most important piece for me is autoFixture which is a great way to stub object.

No more coding huge setup code just for initialize objects. with AutoFixture you can inject your objects into the test and will be automatically populated with data. you can customize the data if you wish.


[Theory, AutoFill]
public async void CompleteAsync_ShouldNotCompleteOrder_WhenCartIsOld(ShippingCart cart)
{
             //test code
}
 

//custom code to return a certain value for a certain property.
//in this case, if propery name is Email, the value should end with @email.com
public class EmailBuilder : ISpecimenBuilder
{
    public object Create(object request, ISpecimenContext context)
    {
        var property = request as PropertyInfo;

        return property?.Name == "Email" ? (object) $"{Guid.NewGuid()}@email.com" : new NoSpecimen();
    }
}

Non production .Net Core API

Credit: Free photo 90033051 © publicdomainstockphotos – Dreamstime.com

In many places that I have worked, there was a need to expose API for testing or building up certain data in non production environment.

One way to do so, is add a project that is not part of the production pipeline.

Another way is to mark certain routes as ‘non production’ routes.

The way we can do that, is to add a custom action filter to determine which environment is allowed:

 public class NonProductionActionFilter : ActionFilterAttribute
    {
        private IHostingEnvironment HostingEnv { get; }
        public NonProductionActionFilter(IHostingEnvironment hostingEnv)
        {
            HostingEnv = hostingEnv;
        }

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            if (HostingEnv.IsProduction())
            {
                context.Result = new NotFoundResult();
                return;
            }

            base.OnActionExecuting(context);
        }
    }

And now we can use this attribute to decorate a controller or a route:

 [TypeFilter(typeof(NonProductionActionFilter))]
    [Route("utilities")]
    [Produces("application/json")]
    public class UtilitiesController : Controller
    {
        ....
    }

And now our Utility controller is only accessible in our QA/Staing/Local environments.