Easy mocking in C# code with FakeItEasy library
Short introduction
Unit tests are inseparable element of software development cycle. They enable testing functionality of the program and bug detection on early stage of implementation. In this article I would like to present mocking library called Fake It Easy but before I present some code, let me do some introduction about terms from unit tests dictionary.
Unit tests dictionary
- Unit of source code - the smallest piece of a code that can be tested. In .NET C# it is usually method or class
- Unit tests - process through which units of source code are tested to verify if they work properly and are free of bugs
- Mocking - process used in unit testing when the unit being tested has external dependencies (cannot work properly without external source code). In .NET C# example can be object of one class which depends on another object from different class. These dependency objects are called "replacement objects"
There are four types of “replacement objects” according to Martin Flower’s article:
- Dummies - objects are passed around but never actually used. Usually they are just used to fill parameter lists in method call
- Fakes - have the same behavior as the thing that it replaces. They have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example)
- Stubs - objects which have a "fixed" set of "canned" responses that are specific to test you setup. They have hard-coded responses to an expected request
- Mocks - have a set of expectations about calls that are made. If these expectations are not met, the test is fail. A mock is not setup in a predetermined way so you have code that does it in your test
Tests written with mocks usually follow below pattern:
initialize -> set expectations -> exercise -> verify
Stub would follow below pattern:
initialize -> exercise -> verify.
…and one more thing: Mocks != Stubs
FakeItEasy library
FakeItEasy is an easy mocking library for .NET which enables creating all types of fake objects, mocks and stubs. I would like to present some cool features of it.
Create Unit Tests project in Visual Studio
FakeItEasy can be used with different testing frameworks. In this case I will use MS Test framework. Rename inital class to “FakeItEasyTests”:
[TestClass]
public class FakeItEasyTests
{
[TestInitialize]
public void TestInitialize()
{
}
[TestMethod]
public void TestMethod1()
{
}
}
Before we start using FakeItEasy I would like to shortly describe class attributes:
- TestClass - attribute which indicated class that contains test methods
- TestInitialize - method which is invoked before each test
- TestMethod - method which contains test code and assertions
Add FakeItEasy NuGet package
FakeItEasy library is available through NuGet packages manager. Install it:
Project is ready! Now its time to see some nice mocking features provided by FakeItEasy.
FakeItEasy library in action
Below I pasted some examples how to use library and how easily you can prepare mocks in the unit tests.
Create fake objects
Creating fake objects with is simple. FakeItEasy enables creating fake objects from:
- interfaces
- classes that are not sealed, static and have at least one public or protected constructor whose arguments FakeItEasy can construct or obtain delegates
Now if fake is created its methods and properties can be overridden under condition that they are:
- virtual
- abstract
- an interface method when an interface is being faked
Let me show simple example. There are four classes:
- Car
- PetrolStation
- Distributor
- Transaction
Car class additionally implements IVehicle interface.
public class Car : IVehicle
{
private string _plateNumber;
public string PlateNumber => _plateNumber;
public Car(string plateNumber)
{
_plateNumber = plateNumber;
}
public void CheckEngineStatus()
{
Console.WriteLine("Engine OK");
}
public void OpenFuelTank()
{
Console.WriteLine("Fuel tank opened");
}
}
public class PetrolStation
{
public Distributor GetDistributorForVehicle(string plateNumber)
{
return new Distributor();
}
}
public class Distributor
{
public virtual decimal getFuelPrice()
{
return 4.50M;
}
public void RefuelTheVehicle(IVehicle vehicle)
{
vehicle.OpenFuelTank();
}
}
public class Transaction
{
private bool _isCompleted;
public decimal getFuelTotalPrice(Distributor distributor, int liters)
{
return liters * distributor.getFuelPrice();
}
public virtual void Finish()
{
_isCompleted = true;
}
}
public interface IVehicle
{
void CheckEngineStatus();
void OpenFuelTank();
}
Now I can easily create fakes in the tests:
var distributor = A.Fake<Distributor>();
var car = A.Fake<Car>(x => x.WithArgumentsForConstructor(() => new Car("WB 82112")));
var petrolStation = A.Fake<PetrolStation>();
var transaction = A.Fake<Transaction>();
var vehicle = A.Fake<IVehicle>();
Please note that I can create fake object from concrete class or from interface - car and vehicle.
Now it is possible to set specific expectations what should happened when invoking concentrate code:
A.CallTo(() => distributor.getFuelPrice()).MustHaveHappenedOnceExactly();
A.CallTo(() => transaction.Finish()).DoesNothing();
In above fragment of code I set expectations that distributor’s “getFuelPrice” method will be called once and “Finish” method call on transaction will have not result or impact.
I can also configure exceptions expectations:
A.CallTo(() => vehicle.CheckEngineStatus()).Throws<NotImplementedException>();
try
{
vehicle.CheckEngineStatus();
}
catch (Exception ex)
{
var exceptionType = ex.GetType();
Assert.AreEqual(exceptionType, typeof(NotImplementedException));
}
Whole sample test method can look like below:
[TestMethod]
public void TestMethod1()
{
var distributor = A.Fake<Distributor>();
var car = A.Fake<Car>(x => x.WithArgumentsForConstructor(() => new Car("WB 82112")));
var petrolStation = A.Fake<PetrolStation>();
var transaction = A.Fake<Transaction>();
var vehicle = A.Fake<IVehicle>();
transaction.getFuelTotalPrice(distributor, 4);
A.CallTo(() => distributor.getFuelPrice()).MustHaveHappenedOnceExactly();
A.CallTo(() => transaction.Finish()).DoesNothing();
A.CallTo(() => vehicle.CheckEngineStatus()).Throws<NotImplementedException>();
try
{
vehicle.CheckEngineStatus();
}
catch (Exception ex)
{
var exceptionType = ex.GetType();
Assert.AreEqual(exceptionType, typeof(NotImplementedException));
}
}
FakeItEeasy provides easy way to create Dummies too so you can use them as a constructor parameters:
distributor.RefuelTheCar(A.Dummy<Car>());
It is also possible to specify return values for method calls:
A.CallTo(() => distributor.getFuelPrice()).Returns(4.5M).Once();
This is just a small piece of features that FakeItEasy offers!
Wrapping up
In this article I explained differences between dummies, fakes, mocks and stubs. I presented great mocking library for .NET C# called FakeItEasy. I encourage you to go through official documentation available here to see more extra features. Pre-configured sample is available on my GitHub.