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();
    }
}

JWT Authentication with .Net Core

credit: Orlando Florin Rosu – Dreamstime.com

So we want to secure our API layer right? we want to write something in one place that will take care of our authentication.

You can use a bearer token and validate each incoming request using a database lookup costly), or you can use JWT token. I like JWT because JWT can store any type of data, which is where it excels in combination with OAuth. With a JWT access token, you need far less database lookups while still not compromising security. You can also can add additional information that will help you avoid database lookups and just pull it from the token.

So here is how a JWT looks like

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0MyIsInVzZXJuYW1lIjoidGVzdDMiLCJ0bWlkIjoiYTA0MzdjYzQtOGQ0MS00YWE5LTk4ZjAtMmIwMjE4NzJmMjdhIiwidWlkIjoiMzkwZGNkMDMtYzgwMC00YTQ1LTVlMmItMDhkNzViZDNhOTZjIiwiZGlzcGxheSI6IlRlc3QgVXNlciIsInJvbGUiOiJBZG1pbiIsImp0aSI6Im15VG9rZW4tNjFjYjNmMWMtNjY2Yy00MTg0LTlmNGMtYTAxMjIxNWNmNDBkIiwibmJmIjoxNTcyMzg2NjYwLCJleHAiOjE1NzI0MDEwNjAsImlhdCI6MTU3MjM4NjY2MCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo2MTEwMy8iLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjYxMTAzLyJ9.bSGhYLOcBR3kwxBAzF4kNme5ZJ3fI9qfJdMsyqHm7d0

And if you take this exact token and paste it on https://jwt.io/ you will see:

You can see on the right side that we can see all the claims (the data) on that token. So in this example, I have my display string for that user, and that saves me database lookups.

The reason we can avoid database lookups, is because JWT contains a base64 encoded version of the data you need to determine the identity and scope of access. When we generate the token, we use a signature (a secret). when reading the token, we must use the same secret. This comparison is way faster than accessing the database to check that the token exists.

Since we don’t have database lookups, we cannot revoke a token. A token is valid until it expires. Hence it is a good idea to have short expiration time for tokens. If you must be able to revoke a token immediately, this is not the best solution for you. It all depends on the system you are working on.

So now that we know what and why to use JWT token. Let’s see how to use it in .Net Core.

In your Startup.cs you will need to add:

public void AddAuthentication(IServiceCollection services)
    {          
        services.AddAuthentication(option =>
        {
            option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        }
          ).AddJwtBearer(options => { 
              options.RequireHttpsMetadata = true;
              options.TokenValidationParameters = JWTConfigurationProvider.TokenValidationParameters(Configuration);
          });
    }

And some code to get the TokenValidationParameters

private static TokenValidationParameters GetTokenValidationParameters(IConfiguration config)
        {
            return new TokenValidationParameters
            {
                AuthenticationType = AuthenticationType,
                ValidateLifetime = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidAudience = Audience(config),
                ValidIssuer = Issuer(config),
                IssuerSigningKey = SymmetricSecurityKey(config,"SigningKey")
            };
        } 

And now we need to add the Authorize attribute on our controller (or routes):

     [Authorize]
     [Route("api/users")]
     [Produces("application/json")]
     public class UsersController : Controller
     {}

And now, every incoming call will be checked if allowed. meaning if the incoming token is what we expect and if still valid.

So how does it work with a client? First off we need to sign in to get a token. That route should not have the Authorize attribute since the user is not logged in yet.

We just call our route with the username and password AND with Basic Auth

The response will be the JWT token from the server.

On our next calls, we need to use that token by using Bearer Token as the type

Since our token expiration time is short, we need to expose a refresh token route. we can use a different route, or just use the same route that can accept both Basic (for the first time the user logs in) and Bearer (for refresh token).

Here is my route to get a token

You can s

[HttpPost]
 [BasicAuthentication]
 [ProducesResponseType(typeof(string), StatusCodes.Status200OK)]
 [ProducesResponseType(typeof(List), StatusCodes.Status400BadRequest)]
 [ProducesResponseType(typeof(List), StatusCodes.Status500InternalServerError)]
 public async Task Post()
 {
     string token = null;
     if (User.Identity.AuthenticationType == Core.Security.JWTConfigurationProvider.AuthenticationType)
     {
         var username = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Username)?.Value;
         if (username != null)
         {
             var roleClaim = (User.Identity as ClaimsIdentity)?.FindFirst(ClaimTypes.Role)?.Value;
             UserRole role = (UserRole)Enum.Parse(typeof(UserRole), roleClaim);
             token = await _service.GetTokenAsync(username, role);
         }
    }
 if (User.Identity.AuthenticationType == "Basic")
 {
     var username = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Username).Value;
     var password = (User.Identity as ClaimsIdentity)?.FindFirst(Core.Security.ClaimTypes.Password).Value;
     token = await _service.GetTokenAsync(username, password);
 }
 if (token.IsEmpty())
     return Unauthorized();
 return Ok(token);
}

You can see that the same route can handle both authentication methods. but how?

The key is adding my own custom BasicAuthenticationAttribute

public class BasicAuthenticationAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
     {
         public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
         {
             await Task.Run(() => Authenticate(authorizationFilterContext));
         }
         private void Authenticate(AuthorizationFilterContext authorizationFilterContext)
         {
             var context = authorizationFilterContext.HttpContext;
             var authHeader = context.Request.Headers["Authorization"][0];
if (authHeader == null || !authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        var token = authHeader.Substring("Basic ".Length).Trim();

        var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token));
        var credentials = credentialstring.Split(':');

        if (credentials.Length < 2)
        {
            authorizationFilterContext.Result = new UnauthorizedResult();
            return;
        }

        var claims = new List
            {
                new Claim(Core.Security.ClaimTypes.Username, credentials[0]),
                new Claim(Core.Security.ClaimTypes.Password, credentials[1])
            };
        var identity = new ClaimsIdentity(claims, "Basic");

        authorizationFilterContext.HttpContext.User = new ClaimsPrincipal(identity);
    }
}

This customer ”’AuthorizeAttribute”’ is reading the token. If the incoming token is Basic (meaning this is the initial log in), we pull the username and password and build a ClaimIdentity with those values.

If it is a JWT token, we do nothing and move on to the controller.

And as we saw before, the controller route is checking which authentication type is coming. If it is a JWT, it means we need to refresh the token (create a new token). If it is a basic type, we need to check that the username and password are valid and create the token.

So now we have one route to handle both refresh and create tokens. Sweet!

Don’t comment (unless you must)

I have not written for a while, but I had this topic on my mind for a while.

It has been on my mind for a while because we (my current workplace) have some mix of new and old code and there are a lot of comments in the old code.

Back in the day, developers were told to add comments, and this something that is changing for the past few years, but our old code was written a while ago. However we do have some ‘older’ guys that still currently add meaningless comments.

Now some comments are helpful but the majority is not needed and it’s just cluttering the code.

I will give some examples (this is real code):

// Check for previously open doors. 
CheckForPreviouslyOpenDoors();

// Post the door opened metered event.
PostDoorOpenMeteredEvent(logicalId, doorName);

You can probably see why those comment are useless. They have zero value.

The reason for not adding any value is because the methods under the comments say it all.

The way to write code in my mind is to keep it simple. Give meaningful names to everything; for properties, for variables and of course to methods.

Now this should always be applied but sometimes we do write complex code within a method (that we gave it a good name of course). In those cases I would add short comments.

Your code should be easy to understand and to follow. Giving meaningful names will help people understand without adding useless comments.