C# standardizing tests - Part 4

Creating tests

Happy path test in the constructor method

Now with our fixture service created with the builder design pattern included inside and also the GetSut method that returns the instance of the service to test, we can begin to perform our tests.

Let's start with the happy path of our constructor. Let's assume that it receives all the correct instances by parameter and should return an instance of our MetadaService and let's also validate that this service is an implementation of the IMetadata interface.

[Fact]
public void MetadataService_Constructor_AllParametersSent_ReturnInstance()
{
    //Arrange
    this.fixture.Reset();

    //Action
    var result = this.fixture.GetSut();

    //Assert
    Assert.NotNull(result);
    Assert.IsAssignableFrom<IMetadata>(result);
    Assert.IsType<MetadataService>(result);
}

As we can see, we have forced the fixture to initialize the services with the Reset method to make sure that whenever the test runs the services have been reset. I know that the fixture constructor invokes the reset, but in a parallel thread execution, the services can fluctuate and be left with garbage data inside.

Wrong paths test in the constructor methods

There are several ways to implement the constructor test when we need each parameter to reach null.

We will see an image describing how to pass data to tests in xUnit.

Data injection allows a single test to create several executions of the same test with a different order of the received parameters.

If you want more information you can visit the following link which gives a more detailed explanation. Pass data in your tests

The implementation we will do is that of Class Data. This allows us to configure the different combinations of parameters.

public class MetadataServiceClassData : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        // All parameters will send null
        yield return new object[] { null, null, null };

        // First parameter null
        yield return new object[] { null, 
                                    new Mock<IUrlUtils>().Object, 
                                    new Mock<IQRImageBuilder>().Object };

        // Second parameter null
        yield return new object[] { new Mock<IUtilities>().Object, 
                                    null, 
                                    new Mock<IQRImageBuilder>().Object };

        // Third parameter null
        yield return new object[] { new Mock<IUtilities>().Object, 
                                    new Mock<IUrlUtils>().Object, 
                                    null };
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

When there is only one parameter per constructor it is not necessary to create this class, it is enough to test the parameter to null.

Now we can create the test that will cover all the erroneous paths when we pass parameters to null, with the different combinatorics created in the ClassData.

[Theory]
[ClassData(typeof(MetadataServiceClassData))]
public void MetadataService_Constructor_SomeNull_ReturnException(params object[] arguments)
{
    //Arrange
    this.fixture.SetService((IUtilities)arguments[0]);
    this.fixture.SetService((IUrlUtils)arguments[1]);
    this.fixture.SetService((IQRImageBuilder)arguments[2]);

    //Action Assert
    Assert.Throws<ArgumentNullException>(() => this.fixture.GetSut());
}

With this, we have finished testing the constructor method with 100% coverage.

We will now create the tests for the coverage of a method implemented in our MetadataService class. See you in part 5...

1
Subscribe to my newsletter

Read articles from Jaime Andrés Quiceno González directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Jaime Andrés Quiceno González
Jaime Andrés Quiceno González

I am motivated Software and Telecommunications Engineer with 9 years of experience in analysis, design, implementation, testing and deployment of software solutions. I am passionate about knowing the context of the problem in detail to end an adequate solution applying SOLID principles and design patterns to deliver software products with quality and efficiency. I have supported and innovated with automation various business and industrial processes through several programming languages and work frameworks with and without Agile methodologies. I have skills and knowledge in both FrontEnd and BackEnd.