I’m trying to Unit Test CRUD operations for an API in my WEB API project. I have a hard time figuring out how to do that for DELETE. Below is my service;
public async Task DeleteCompany(int id)
{
var query = "DELETE FROM Companies WHERE Id = @Id";
using(var connection = _context.CreateConnection())
{
await connection.ExecuteAsync(query, new {id});
}
}
Here’s the controller
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteCompany(int id)
{
var company = await _companyRepository.GetCompanyById(id);
if (company == null)
{
return NotFound();
}
await _companyRepository.DeleteCompany(id);
return NoContent();
}
And below is the code for Unit Testing
[Theory]
[InlineData(1)]
public async Task CompanyController_DeleteCompany_ShouldReturnStatusCode204(int id)
{
var mockCompany = new Mock<ICompanyRepository>();
mockCompany.Setup(service => service.DeleteCompany(id))
.Returns(Task.CompletedTask)
.Verifiable();
var sut = new CompanyController(mockCompany.Object);
var result = (OkObjectResult) await sut.DeleteCompany(id);
result.StatusCode.Should().Be(204);
}
It turned out that it returns a null value of my model (Company in this example) after debugging. That’s why the test doesn’t pass and it gets to NotFound error in the controller.
>Solution :
You need to set up the Test Double‘s GetCompanyById method so that it doesn’t return null:
[Theory]
[InlineData(1)]
public async Task CompanyController_DeleteCompany_ShouldReturnStatusCode204(int id)
{
var mockCompany = new Mock<ICompanyRepository>();
mockCompany.Setup(service => service.GetCompanyById(id))
.ReturnsAsync(/*pass non-null value here*/);
var sut = new CompanyController(mockCompany.Object);
var result = (OkObjectResult) await sut.DeleteCompany(id);
result.StatusCode.Should().Be(204);
mockCompany.Verify(service => service.DeleteCompany(id);
}
On the other hand, you don’t need to set up DeleteCompany as a verifiable action since it doesn’t return anything anyway. Mocks for Commands, Stubs for Queries. Use mockCompany.Verify instead, as shown above.