I am just working on testing some Web Api controllers. However, I cannot seem to find what is the problem with being able to set the return values to be a list. When debugging, the output of ClassSql.ReadAllClassesAsync() is not being faked for some odd reason. If I test a the method ClassSql.ReadClassAsync() that only returns a single value, the faking works perfectly. Hence, all my tests work.
The controller is:
public class ClassController : ControllerBase
{
private readonly IClassSqlService ClassSql;
private readonly ILogger<ClassController> Logger;
public ClassController(
IConfiguration config,
ILogger<ClassController> logger,
IDataAccessAbstractFactory<IClassSqlService> classSql)
{
string SMString = config.GetValue<string>(DataAccessName.SMCnx)!;
Logger = logger;
ClassSql = classSql.Create(SMString);
}
[HttpGet]
[ProducesResponseType(200, Type = typeof(List<ClassModel>))]
public async Task<ActionResult<List<ClassModel>>> ReadAllClasses(
string? academic_year = null)
{
List<ClassModel> output;
if(academic_year is not null)
{
bool isIdValid = int.TryParse(academic_year, out int year);
if (isIdValid is false)
return BadRequest();
output = await ClassSql.ReadAllClassesByAcademicYearAsync(academic_year);
}
else
{
output = await ClassSql.ReadAllClassesAsync();
}
if (output.Any() is false)
return NotFound();
return Ok(output);
}
}
My unit testing is as follows:
public class ClassControllerTests
{
private readonly IClassSqlService ClassSql;
private readonly ClassController sut;
public ClassControllerTests()
{
var config = A.Fake<IConfiguration>();
var classSql = A.Fake<IDataAccessAbstractFactory<IClassSqlService>>();
var logger = A.Fake<ILogger<ClassController>>();
sut = new ClassController(config, logger, classSql);
ClassSql = classSql.Create(string.Empty);
}
[Fact]
public async Task ReadAllClassesShouldReturnOk()
{
// arrange
var classes = A.CollectionOfFake<ClassModel>(5);
A.CallTo(() => ClassSql.ReadAllClassesAsync()).Returns(classes.ToList());
// action
var result = await sut.ReadAllClasses();
// assert
result.Result.Should().NotBeNull();
result.Result.Should().BeOfType(typeof(OkObjectResult));
result.Value.Should().NotBeEmpty();
}
}
I have read the documentation of FakeItEasy and followed their example with faking collections but no success.
Any help would be amazing.
Thank you.
When debugging, the output of the controller is not being faked for some odd reason
Can you explain what this means? Also, it's not clear what result you do get. Which of the assertions at the end of the test fail? How?
I'm not sure what the difference between your single-value and multi-value returning tests (or production methods) is, but I'll note one thing. I suspect it's your problem.
In your test code, you create a fake IClassSqlService
called ClassSql
(in a sort of roundabout way, by calling Create
on a fake IDataAccessAbstractFactory<IClassSqlService>
).
Inside ClassController
, classSql.Create(SMString)
is called to make a different IClassSqlService
called ClassSql
.
The test configures the first ClassSql
to return classes.ToList()
. The controller calls the second ClassSql
whose unconfigured ReadAllClassesAsync
, I'm guessing, returns a fake list of ClassModel
s, and it acts like it's empty.