Skip to content

.NET Core and xUnit: Some Basic Refactoring

The following is the structure of the typical xUnit test method I started with, and it's something I've seen a few other developers do also:

[Fact] 
public void TestComputerSearch()
{
      List<Computer> mockComputers = new List<Computer>()
      {
            new Computer()
            {
                  ...
            },
            new Computer()
            {
                  ...
            }
      };
      ...
      Here be test code
      ...
      Assert.Equal(returnModel, mockComputers);
}

Obviously when the mockComputers list contains multiple items, the test method doesn't look good. It looks worse the more items we add. Nobody wants to scroll through numerous lines of test data to determine what a unit test class actually does. And there's too much duplication in the code, which usually isn't a good thing. The test data needs to be moved elsewhere, and in a way that enables it to be re-used instead of duplicated.

Using Visual Studio's 'Quick Actions and Refactorings...' (because it's quicker), I extracted the constructors to separate methods. eg.

private static List<Computer> MockComputers() 
{
      return new List<Computer>()
      {
            new Computer()
            {
                  ...
            },
            new Computer()
            {
                  ...
            }
      };
}

And called it in the test method like so:

[Fact] 
public void TestComputerSearch()
{
      List<Computer> mockComputers = MockComputers();
      ...
      Assert.Equal(returnModel, mockComputers);
}

Having done this for all the mock data constructors, I ended up with something like the following in the unit test class:

private static Computer MockComputer()...
private static List<Computer> MockComputers()...
private static Lab MockLab()...
private static User MockUser()...
private static List<ComputerLab> MockComputersToLabs()...

The unit test project can be made a lot cleaner still, if the above methods are moved to a separate class, and we a test method file (FunctionTests.cs) and a test data file (MockData.cs).

In MockData.cs, I added a new class just for the test data:

namespace MyApplication.Test.Data
{
    public class MockData
    {
    }
}

Then moved the mock data methods to that class and changed them from private to public:

public class MockData 
{
      public static Computer MockComputer()...
      public static List<Computer> MockComputers()...
      public static Lab MockLab()...
      public static User MockUser()...
      public static List<ComputerLab> MockComputersToLabs()...
}

In FunctionTests.cs, I changed the references to them in the test methods. e.g.

... Lab mockLab = MockData.MockLab(); List mockComputers = MockData.MockComputers() List mockComputersToLabs = MockData.MockComputersToLabs(); ...