Back in part 1 I jokingly closed with a test passing, but I was cheating a bit by building a method that returns a hardcoded string containing the expected result. This is perfectly acceptable in the initial phase to make a test pass, if only to be sure that the rest of the scaffolding was done correctly.

While driving home that day in the style of Papa Pig, an idea starts forming. What if we write another test to check for a second case? Back in the office the next day we add this test case for the fictional outlet with an id of 2. We need to change the test method into a parametrised test method:

[Theory]
[InlineData(0, "4/28/2019 10:00")]
[InlineData(1, "4/28/2019 12:00")]
public void Outlet_can_show_the_time_according_to_its_local_timezone(
    int outletId, string expectedResult)
{
    var result = sut.GetLocalDateTime(outletId);
    result.Should().Be(expectedResult);
}

In this way we may use the same test for multiple values. If we run the tests only one is passing, so we have a problem once more.

Only one of the two tests is passing

Let’s solve the problem properly this time. What we need is another layer of indirection. The Outlet class was directly dependant on the System.DateTime class, and with our change we only made it dependant on the DateTimeWrapper class. We still cannot control the behaviour of the date within our test. We need to add an interface that specifies the wrapper’s behaviour and then we will be able to mock it during the test execution. Visual Studio has a nice refactoring tool that allows us to quickly generate the interface:

Extracting the DateTimeWrapper Interface

It even allows us to choose the name and which methods to include in the interface:

We also have some control when extracting the interface

To be honest, I'm not sure if this feature is standard in all versions of Visual Studio, but here is the generated code anyway:

using System;

namespace TimeZoneHelper
{
    public interface IDateTimeWrapper
    {
        DateTime Now();
    }
}

That’s it, and the DateTimeWrapper class now also inherits the IDateTimeWrapper interface. Let’s use it! In the Outlet class change the type to IDateTimeWrapper:

public class Outlet
{
    private readonly IDateTimeWrapper dateTimeWrapper;

    public Outlet(IDateTimeWrapper dateTimeWrapper)
    {
        this.dateTimeWrapper = dateTimeWrapper;
    }

    public string GetLocalDateTime(long id)
    {
        return dateTimeWrapper.Now().ToString("M/d/yyyy HH:mm");
    }
}

Now any object that implements IDateTimeWrapper can be used with the Outlet class. Note that the choice for initialising the required wrapper class will be handled by the dependency injection middleware, but we won’t go into it here as we will just focus on the test.

In the test class, we will also use the interface, but on top of that we will mock it as well. It’s not that we want to make fun of it, we just want to be able to control what happens during the test. We will now use NSubstitute, which makes the task of creating mocks easier. Let us change the code inside the test constructor:

public OutletTest()
{
    var wrapper = Substitute.For<IDateTimeWrapper>();

    sut = new Outlet(wrapper);
}

We are still not specifying the behavior of the wrapper, so both tests are failing. Let’s add this behaviour, so now we can specify what the date is every time we run the test. With NSubstitute again, the code is nice and readable:

public OutletTest()
{
    var wrapper = Substitute.For<IDateTimeWrapper>();

    wrapper.Now().Returns(new DateTime(2019, 4, 28, 17, 00, 00, DateTimeKind.Utc));

    sut = new Outlet(wrapper);
}

So we have specified that every time we run the test, the UTC time is always April 28th 2019 at 17:00. We have gone through all this trouble but still the tests fail. That is because we did not implement any logic in the Outlet class, but now we have done enough groundwork to let us do that efficiently. The main point I wanted to show you was about removing hard dependencies to system objects and now we have achieved that. See you in part 3!

This post is based on a short talk I gave some months ago. Let’s say we have a client with a website hosted in one location in Azure. This client has multiple sub-domains associated with physical locations spread across the US. And there is a requirement that each sub-domain displays the time according to the timezone of its associated outlet.

Image source: http://time-time.net/times/time-zones/usa-canada/usa-time-zone-map.php

Let’s start by creating a new demo solution using the following steps in VS2019:

Create a new class library. I named my solution TimeZoneHelper. Then add a new xUnit test project to the solution

Adding a test project to the solution

On the test project, right click and choose ‘Manage NuGet packages’. Install the NSubstitute and FluentAssertions packages.

Installation of the required nuget packages for testing

We also need to reference the class library from the test project:

Referencing the base project

In the TimeZoneHelper project, add a new class named Outlet.cs with the following code:

using System;

namespace TimeZoneHelper
{
    public class Outlet
    {
        public string GetLocalDateTime(long id)
        {
            throw new NotImplementedException();
        }
    }
}

Note that I want to keep things as simple as possible to follow. In a real-life scenario, I would probably use a property to hold the id of the outlet rather than passing it around and keep the return type as DateTime with the proper timezone offset. The GetLocalDateTime method just throws an exception. We need to do this otherwise the solution will not compile. Otherwise, if the solution does not compile, we cannot test it. So let’s write the first test.

using FluentAssertions;
using TimeZoneHelper;
using Xunit;

namespace TimeZoneHelperTest
{
    public class OutletTest
    {
        private readonly Outlet sut;

        public OutletTest()
        {
            sut = new Outlet();
        }

        [Fact]
        public void Outlet_can_show_the_time_according_to_its_local_timezone()
        {
            var result = sut.GetLocalDateTime(1);
            result.Should().Be("4/28/2019 17:00");
        }
    }
}

In this test, we are initialising the Outlet class and calling its method to check if we get back the result that we wanted. Two things to note. As a convention, I usually use sut (system under test) or target for the variable that is used to hold the class to be tested. Second, note that by using FluentAssertions the test assertion is a very readable, i.e. result.Should().Be(...) rather than Assert.Equal(...).

Initial failing test

As expected, the test fails because we’re just throwing an exception. So let’s change that line of code with this:

public string GetLocalDateTime(long id)
{
    return DateTime.UtcNow.ToString("M/d/yyyy HH:mm");
}

Running the test, we see a different result, but it still fails:

Test still failing

The reason now is that I am expecting to get a particular point in time, but my current time is different. So this test will only be successful at exactly one point in the history of the world which is not very useful. Otherwise, I would have to change the expected value every time that I run the test, which is not very useful either. And I’ve seen people do this, but we won’t, so don’t even think about it.

The Outlet class is reading the current system’s date and time directly from the System object. Let’s try to uncouple the dependency between the two by introducing another object. Enter DateTimeWrapper.cs:

using System;

namespace TimeZoneHelper
{
    public class DateTimeWrapper
    {
        public DateTime Now()
        {
            return DateTime.UtcNow;
        }
    }
}

The Outlet class can now be modified to use the DateTimeWrapper:

public class Outlet
{
    private readonly DateTimeWrapper dateTimeWrapper;

    public Outlet(DateTimeWrapper dateTimeWrapper)
    {
        this.dateTimeWrapper = dateTimeWrapper;
    }

    public string GetLocalDateTime(long id)
    {
        return dateTimeWrapper.Now().ToString("M/d/yyyy HH:mm");
    }
}

In this way, the Outlet object does not need to be concerned with how the date is fetched and this responsibility is shifted to the DateTimeWrapper. If we need to change how the date is fetched in the future, perhaps because we found a better way to do it, then we won’t need to touch the Outlet class, which is good. However, at this point the logic is mostly the same as before, so the test still fails with the same outcome. Note that the test constructor now needs to initialise the DateTimeWrapper as well:

public OutletTest()
{
    sut = new Outlet(new DateTimeWrapper());
}

Now is the time that I would typically start cheating. Let’s modify the Now method in the DateTimeWrapper:

public DateTime Now()
{
    return new DateTime(2019, 4, 28, 17, 00, 00);
}

With this change, the test passes.

Test is passing!

We have done our job and we can all go home to rest. We may also brag about our cool code to anyone we are lucky to meet on our way out of the office.

Did we solve our problem completely? Or will we face an unexpected setback? Find out in part 2.

I clearly remember when I started my first job way back almost 30 years ago. At that time, computers didn’t have such a major role in the work environment. Although I was always into software development, there were a lot of engineering jobs. So that’s what I ended up doing. I worked for a telephone company, and the first task I was given was cleaning this thing from used wires so that it can be reused again:

That’s called a distribution frame, and what I had to do is to pull out the wires with a hook. These boxes were used in pairs, one for connecting the telephone system and one for the actual distribution to each telephone. Each 2-wire point was connected from one distribution box to the other to make a path from the system to the actual phone.

And we were instructed to wire everything neatly. And we used colour coding as well, so the same coloured wires would be always in the same spot for all installations, and it would be easy to spot mistakes and to maintain. Sometime later, patch leads with plastic (RJ11) connectors became the norm. And after spending a day patching the system we used to be proud of our work. A cabinet such as this one is such a joy to behold:

A neat installation

We often suggested to our clients to invest in proper cabinets with cable trays and room to work properly. However I also know that it costs money and is not always easy to justify the spending against cheaper alternatives. I remember this one time when we provided a quote which was double that of our competitor. The labour cost of our competitor was almost non-existent, and the customer chose the cheaper option.

When the work was finished it looked like this:

A messy installation

Of course, everything worked initially and the competitor was promptly paid. The problems started after some time when trying to patch a phone to a new location required hours of work trying to find the correct patch lead and untangle it from the rest. Eventually, it got out of control, our competitor admitted that they focused on installations rather than maintenance work and suggested that the customer gets in touch with us.

We were happy to help, and the customer, in the end, was happy too. Although we did charge extra for cleaning the existing installation on top of the original quote.

I did write a lot of software during the next few years, both for the telephone company as well as a freelancer. Fast forward some more years and I wanted to find a full-time development job. You know, I thought programmers are cool and earn big bucks, but mostly I wanted to do it to gain experience. I wanted to learn how the pros write their software and I wanted to become one of them.

That’s when I realised that a lot of the software industry just tries to earn a quick buck by delivering stuff quickly (and breaking things along the way). It reminds me of the wiring incident all those years before. Since then I have been looking for information about writing clean code. Code that does not only work well the first time but also after every time it needs modifications.

I have been following a number of people who have been trying to teach us what it means to be a professional coder. People like Martin Fowler, Uncle Bob, Kevlin Henney, and recently Kate Gregory to name a few. If you have never done so before, I suggest that you take your time to discover and realise what writing good code means. And how it will benefit the long term health of your project. This is much more important than learning the next big language or framework that can do this and that other new thing. This is about tidiness in your work, and going back home at the end of the day with something that you are proud with.

So the moment that I was waiting for has finally arrived. I picked up my courage and pressed the publish button of the .NET Core project. Then soon after, this happened:

The main message from this chart is that before publishing this version, the average response time of the site running on ASP.NET MVC 5 was between 90 and 100ms. With ASP.NET Core 2.2 we can see that the average is now around the 20ms mark.

That’s an improvement factor of 5X, and the best part of it is that there is minimal change in code. And this code is mainly updating references from System.Web to Microsoft.AspNetCore (see my previous blog entries to know more about these tweaks). And I also have to admit that this is running on the smallest paid tier.

So now the fun part starts, trying to improve the performance even further through my own changes.

As promised last time, I’m going to talk about HTML helpers on ASP.NET Core. If you’ve never heard about helpers before you may be thinking about another kind of helper perhaps:

However, I’m talking about the kind of helper which helps you write code once and re-use it in multiple places. The two biggest advantages with helpers are that they keep the page output consistent and when the time comes to change something you only need to change it in one place. Code repetition is not good and never fun.

Tag helpers seem to be the cool thing to do with .NET Core, but remember that I am looking to convert the site from MVC 5 with minimal changes and if possible do everything without touching the views.

The first required adjustment was to change the helper type to IHtmlHelper and the return type to IHtmlContent. That is good since in both cases the change is minimal, and because by using interfaces the helper is not directly dependant on any particular type as long as the type implements the interface.

The major problem that I faced was with the TagBuilder’s InnerHtml property: it’s readonly. No big worries though. Once I noticed that this was a dead end, changing the helper to build the content via a StringBuilder instead proved to be very easy. The last fix was to change the return object from MvcHtmlString to HtmlString.

Once that was done, it was just a case of running the solution and this permitted me to confirm that everything was actually working as wanted.

One final step that I want to sneak in is adding Application Insights to the solution. We are almost done with the changes, so adding monitoring to start gathering some data makes sense at this point. There is also tooling in Visual Studio to help with this. The easiest way is to right-click on the project and Add > Application Insights. Since I was already using Insights on the previous solution, this was also detected and the existing instrumentation key was easily picked up and configured by the editor. Next time, let’s get ready to publish the changes!

Buy me a coffee Buy me a coffee