Interfaces for better unit tests

Alisa Schulz

27/06/2023

In this blog post, I'd like to use a simple example to show you how you can use interfaces in C# to enable independent testing of individual classes in your C# projects. The example builds on my last post, "Getting started with unit testing in C# – Setup, basics and helpful tools" on.

Why should unit tests be run independently of the class?

The purpose of unit tests is to independently test individual sections of code for their functionality. However, classes or methods may depend on another class. In these cases, the code sections cannot be tested independently. This is particularly problematic if the class on which the section we are testing depends is not yet fully tested, contains errors, or perhaps hasn't even been implemented yet.

The following example shows how the NuGet package “FakeItEasy” and interfaces can be used to test classes independently.

 

Example – The class to be tested depends on another class

In this example, which is based on the blog post: "Getting Started with Unit Testing in C# – Setup, Basics, and Helpful Tools," we have our test class, Calculator (Figure 1). We want to test the method Calc(int n1, int n2, operation operation) for the case of addition. Calc(int n1, int n2, operation operation) calls a method of an instance of the Addition class (Figure 2), which is incorrectly implemented, causing our method Calc(int n1, int n2, operation operation) to return a false value.

The unit test from Figure 3, which tests the method Calc(int n1, int n2, operation operation), also depends on the class Addition and not exclusively on our class Calculator.


Figure 1 The class Calculator to be tested has an object of the class Addition and uses this in the method Calc to calculate the result


Figure 2 The Addition class, on which our Calculator class depends, is incorrectly implemented and returns the number 0 as the return value for each call to the Add(int n1, int n2) method


Figure 3 The unit test for testing the method Calc(int n1, int n2, operation operation) fails because the class Addition returns the wrong result

The test in Figure 3 will fail if we run it—not because our method Calc(int n1, int n2, operation operation) is incorrectly implemented, but because the error lies in the Addition class. Our unit test cannot pass as long as the Addition class is not correctly implemented.

 

Example – Using an interface to enable independent testing

To be able to test our method Calc(int n1, int n2, operation operation) independently, we create an interface IAddition (Figure 4). This interface defines the interface between the Calculator and Addition.


Figure 4 Interface to define the interface to the class Addition

As shown in Figure 5, the Addition class inherits from the IAddition interface. Therefore, the Addition class is required to implement a method Add(int n1, int n2) with a float return value.


Figure 5 Our class Addition now inherits from the interface IAddition

In the Calculator class, we now change the type of the variable Addition to IAddition. We can still initialize it with an object of type Addition, since the Addition class inherits from the IAddition interface.


Figure 6 Changing the type of the variable Addition in our calculator

 

What does this mean for our test? We can now "mock" our interface using the NuGet package FakeItEasy, meaning we can create an object that implements this interface. In Figure 7, in the Arrange block, line 27 creates a mock instance called fakeAddition that implements the IAddition interface. The variable Addition from our Calculator is then replaced with fakeAddition in line 28. Furthermore, in line 30, we specify that if our fakeAddition calls the Add method with the input parameters number1 and number2, the value (number1 + number2) should be returned.


Figure 7 Adaptation of the unit test to create a mock object of type IAddition and use it instead of the class Addition

This unit test will now pass when executed, as it no longer accesses the Addition class, but instead accesses our mock object, fakeAddition. Our Calculator class can now be tested successfully and independently of the Addition class.

 

Examples – What else can be mocked with FakeItEasy

FakeItEasy offers many options for making tests more detailed and comprehensive. Using interfaces and FakeItEasy, we can create mock instances and specify how they should behave. Below are a few examples of what can be specified for mock instances.

  • We can specify how often a method of an interface may be called in order for the test to pass
    A.CallTo(() => fakeAddition.Add(A.Ignored, A.Ignored)).MustHaveHappened(1, Times.Exactly);
  • We can set return parameters of a method for specific input parameters
    A.CallTo(() => fakeAddition.Add(number1, number2)).Returns(number1 + number2
  • We can set return parameters of a method for any input parameters
    A.CallTo(() => fakeAddition.Add(A.Ignored, A.Ignored)).Returns(3);
  • We can specify a sequence of return parameters for a method, which should be returned one after the other regardless of what the input parameters are
    A.CallTo(() => fakeAddition.Add(A.Ignored, A.Ignored)).ReturnsNextFromSequence(new float[] { 0.1f, 0.4f, 0.0f });
  • We can specify exceptions that should be thrown when a method of our mock instance is called
    A.CallTo(() => fakeAddition.Add(A.Ignored, A.Ignored)).Throws();

Further ways to use FakeItEasy and examples can be found at: https://fakeiteasy.github.io/docs/7.3.1/

Conclusion

We can use interfaces specifically to define interfaces between classes. These interfaces ensure the independent testability of these classes. Using FakeItEasy, interfaces can be used to control the flow of information through the interface during unit tests. This allows us to, for example, specify return parameters for specific function calls, control how often the functions of an interface can be called, and much more.


Written by Alisa Schulz


More articles

  • 26/11/2025
  • General, Hardware, Standards, Quality, Testing

Why EMC testing is vital in medical technology: Imagine a patient is lying in the hospital during critical monitoring. Suddenly, a visitor's smartphone rings – and the monitoring device... ...

Read more
  • 20/11/2025
  • General, Hardware, Quality, Technology, Testing

Have you ever considered sourcing inexpensive components from China? The temptation is strong, we know that. And we've already gained some experience, from which I... ...

Read more
  • 13/11/2025
  • General, manufacturing, production, quality, company

In our globalized world, relocating medical technology manufacturing to the Far East seems attractive at first glance: large production capacities and favorable prices. For many years, offshoring has also been ...

Read more
Privacy Overview

This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.

Strictly Necessary Cookies

Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.