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.
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.