C# standardizing tests - Part 1

Intro

Hello everyone. This is the first part of a series of posts that will explain a methodology that allows implementation tests in an organized way, with separate responsibilities and using most of the available resources that XUnit tests have. I hope you find it useful. let's get started!

Describing the problem to solve

In most companies, testing becomes essential to ensure code coverage and the proper functioning of implemented features.

However, tests can have very high complexity and may contain some logics in their implementation that forces you to pause reading the test to understand what you want to test.

Example test

As you can see in the test above, we find multiple responsibilities implemented:

  • Creation of class instances

  • Creation and configuration of Mock objects

  • Hardcoded values

  • And finally, the validations corresponding to the test.

If you spend some time, you might get an idea of what you are testing. But it has not forced you to read carefully.

Therefore, we will implement the tests for complete code coverage and with an enterprise-wide specific standard.

General architecture to implement

The proposal consists of using the inheritance of ClassFixture, where T will be replaced by a class or service that we will call fixture, usually with a name composed of the name of the class to be tested together with the word Fixture at the end. This class will be in charge of containing all the necessary logic to deliver to the test, the object or test subject; that is to say, an instance of the class to be tested.

The fixture class allows the configuration of the services before obtaining the instance of the service through a design pattern called Builder which will be explained in another section; in addition, it can communicate with other services to obtain the mocked data that we want to return in the configured services and create instances of Fake services.

On many occasions, we may need to create a Fake service that returns an X value or executes a Y process. This usually occurs when we have abstract classes and we do not need to test them, we only need them to return or execute some logic when invoked by our tested instance.

To better structure the tests we will separate them into folders by responsibility as follows for each service:

  • ServicesTests

    • MetadataService

      • Fakes

        • QueryBuilderFake (Example)
      • Fixtures

        • MetadataServiceFixture
      • Mocks

        • MetadataServiceMocks
      • Implementations

        • MetadataServiceTests

We will go step by step to achieve the implementation of this methodology, first, let's take a look at some standards in terms of code organization. See you in part 2...

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.