Returning multiple fake objects with FakeItEasy
I was recently writing some unit tests where I needed to test that multiple calls to an interface returned different objects.
With FakeItEasy this is easy:
A.CallTo(() => myInterface.GetSomething(1)).Returns(new Something())
All very nice, but now if I have multiple calls to myInterface
I have to execute the above statement ‘x’ amount of times:
[Fact]
public void Should_Do_Something()
{
var myInterface = A.Fake<IApplication>();
A.CallTo(() => myInterface.GetSomething(1)).Returns(new Something());
A.CallTo(() => myInterface.GetSomething(2)).Returns(new Something());
A.CallTo(() => myInterface.GetSomething(3)).Returns(new Something());
var result = sut.DoSomething(myInterface);
Assert.Equal("Super Duper", result);
}
There is a tidier way to do the above where you can return specific objects and its called ReturnsLazily
. Lets take a look at this:
public class Employee
{
public string Name { get; set; }
}
public interface IEmployeeRepository
{
Employee GetEmployeeById(int id);
}
public class App
{
private readonly IEmployeeRepository employeeRepository;
public App(IEmployeeRepository employeeRepository)
{
this.employeeRepository = employeeRepository;
}
public string GetNamesAsCsv(int[] ids)
{
var employees = ids.Select(id => employeeRepository.GetEmployeeById(id).Name);
return string.Join(",", employees);
}
}
public class AppTests
{
[Fact]
public void AppReturnsNamesAsCsv()
{
//Given
var employees = new Dictionary<int, Employee>
{
{ 1, new Employee { Name = "Moss"} },
{ 2, new Employee { Name = "Roy"} },
};
var fakeRepository = A.Fake<IEmployeeRepository>();
A.CallTo(() => fakeRepository.GetEmployeeById(A<int>.Ignored))
.ReturnsLazily<Employee, int>(id => employees[id]);
var app = new App(fakeRepository);
//When
var result = app.GetNamesAsCsv(employees.Keys.ToArray());
//Then
Assert.Equal("Moss,Roy", result);
}
}
We have an Employee
object, a IEmployeeRepository
which returns an Employee
object and an App that returns a CSV. We then want to test this and make sure we get back a CSV from multiple objects.
So we set our fake setup and say that when GetEmployeeById
is called we want to return a specific object. Our App class will call GetEmployeeById
twice with the id of 1 and 2. This is done by passing in employees.Keys.ToArray()
to our GetNamesAsCsv method under test.
When this is called with the id we want to return specific objects .ReturnsLazily<Employee, int>(id => employees[id]);
This says we want to return an Employee and the argument in the repository call is an int. We can then use that to return a specific object based on that id which is where the Dictionary<int, Employee>
comes in handy. Based on the key it will return either an Employee called Moss or Roy. Our GetNamesAsCsv
will then join Moss & Roy together as a CSV and we can assert that our method works.
Hope that helps someone!
comments powered by Disqus