Reputation: 83
I have some problems testing a singleton. When I run this code, I get an error in TestGetLogicalDevices(). CallTo() failed because service is no fake object. When I try to create a fake object (commented code), it gives an error because RestService is a singleton with private constructor. How can I create a fake object of this singleton?
private RestService service;
[TestInitialize]
public void Init()
{
//service = A.Fake<RestService>();
service = RestService.Instance;
service.CreateClient("test", "test");
}
[TestMethod]
public async Task TestGetLogicalDevices()
{
var logicalDevices = (List<LogicalDevice>)A.CollectionOfFake<LogicalDevice>(10);
A.CallTo(() => service.GetLogicalDevices()).Returns(Task.FromResult(logicalDevices));
List<LogicalDevice> collectedData = await service.GetLogicalDevices();
Assert.AreEqual(2, collectedData.Count);
}
public async Task<List<LogicalDevice>> GetLogicalDevices()
{
var response = await client.GetAsync(apiBaseUrl + "/logical-devices");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
var logicalDevices = JsonConvert.DeserializeObject<List<LogicalDevice>>(json);
var sortedList = logicalDevices.OrderBy(logicalDevice => logicalDevice.Name).ToList();
return sortedList;
}
else
{
return null;
}
}
Update I added the code of my method I want to test. Maybe someone has suggestions for better tests?
Upvotes: 4
Views: 1227
Reputation: 292405
Note: I'm not sure I understand what you're trying to do. What are you trying to test exactly? In your test, you configure service.GetLogicalDevices()
to return something, then you call service.GetLogicalDevices()
and assert what it returns (which, unless FakeItEasy is broken, should be what you configured it to return). So, you're not actually testing the service... you're testing the mocking framework! Mocking frameworks like FakeItEasy are useful to mock the dependencies of the system under test (SUT), not the SUT itself. In your case, if the SUT is RestService
, you need to mock the dependencies of RestService
, not RestService
itself. For instance, you could inject an HttpClient
with a HttpMessageHandler
that you control (see here for more details).
Now, to answer your actual question (assuming it's really RestService
that you want to fake):
When I run this code, I get an error in TestGetLogicalDevices(). CallTo() failed because service is no fake object.
A.CallTo
only works on fakes; FakeItEasy can't control the behavior of objects it didn't create.
When I try to create a fake object (commented code), it gives an error because RestService is a singleton with private constructor
RestService
is a class, and FakeItEasy can create a fake for a class, but it does it by inheriting the class, so it needs an accessible constructor. Also, keep in mind that only virtual methods can be configured. GetLogicalDevices
is not virtual, so the fake can't override its behavior.
You have two main options for faking RestService
:
protected
rather than private
, and make the methods virtual so that they can be overridenIRestService
interface that represents the "public contract" of the RestService
class, and fake that interface instead of the class.Upvotes: 4