Home > Back-end >  How can I write unit Tests in .NET for web api
How can I write unit Tests in .NET for web api

Time:04-29

My controller for the delete method :

[HttpDelete("{toDoListId}")]
    public async Task<ActionResult> DeleteToDoList(int toDoListId)
    {

        var toDoListEntity = await _toDoListRepository.GetSpecificTodoAsync(toDoListId);
            
        if (toDoListEntity == null)
        {
            return NotFound();
        }
        _toDoListRepository.DeleteToDoList(toDoListEntity); 
        
        await _toDoListRepository.SaveChangesAsync();
        return NoContent();

    }

My repository :

public async Task<ToDoList?> GetSpecificTodoAsync(int taskId)
    {
        return await _context.ToDoLists.Where(c => c.Id == taskId).FirstOrDefaultAsync();
    }

public void DeleteToDoList(ToDoList toDoListDto)
    {
        _context.ToDoLists.Remove(toDoListDto);
    }

My testcase for checking if the item got deleted and if it returns no content after being deleted. But both of my test cases are failing. Any help on how to write test cases for the delete part, I would be really grateful. I am also trying to test other methods but I am unfortunately stuck here. Please kindly help me

public class UnitTest1
    {
 
        private readonly Mock<IToDoListRepository> repositoryStub = new ();
        private readonly Mock<IMapper> mapper = new Mock<IMapper>();
        private readonly Random Rand = new();
        private ToDoList GenerateRandomItem()
        {
            return new()
            {
                Id = Rand.Next(),
                Description= Guid.NewGuid().ToString(),
                Title = Guid.NewGuid().ToString(),
                StartDate = DateTime.Now,
                EndDate = DateTime.Now,
                Done = false
            };
        }

 [Fact]
        public void Delete_removesEntry()
        {
            //arrange
            var existingItem =  GenerateRandomItem();
            
            var controller = new ToDoController(repositoryStub.Object, mapper.Object);
            var itemID = existingItem.Id;

            //act
            controller.DeleteToDoList(itemID);

            //assert
            
            Assert.Null(repositoryStub.Object.GetSpecificTodoAsync(itemID));

        }
        [Fact]
        public async Task DeleteItemAsync_WithExistingItem_ReturnNoContent()
        {
            //Arrange
            var existingItem = GenerateRandomItem();
            repositoryStub.Setup(repo => repo.GetSpecificTodoAsync(existingItem.Id)).ReturnsAsync((existingItem));

            var itemID = existingItem.Id;
            var controller = new ToDoController(repositoryStub.Object, mapper.Object);
            //Act

            var result = await controller.DeleteToDoList(itemID);

            //assert
            result.Should().BeOfType<NoContentResult>();

        }

CodePudding user response:

Both test cases are failing because the mock has not been setup to behave as expected for each test case.

There is also a potential race condition in the shown tests since they are sharing the same mock instance. This will cause issues when setting up the mock as one test case could potentially override the setup of another case.

Update the tests so that they are isolated from each other.

In the first test, the expected behavior can be verified by checking the mock to see if the expected member was invoked.

[Fact]
public async Task DeleteToDoList_Should_RemoveEntry() {
    //arrange
    ToDoList existingItem =  GenerateRandomItem();
    var itemID = existingItem.Id;
    
    Mock<IToDoListRepository> repositoryStub = new ();
    
    //Setup expected behavior of mock
    repositoryStub
        .Setup(_ => _.GetSpecificTodoAsync(itemID))
        .ReturnsAsync(existingItem);
    
    var controller = new ToDoController(repositoryStub.Object, mapper.Object);

    //act
    await controller.DeleteToDoList(itemID);

    //assert
    repositoryStub.Verify(_ => _.DeleteToDoList(existingItem));
}

In the other test, the mock needs be setup to make sure the subject executes to completion.

[Fact]
public async Task DeleteToDoList_WithExistingItem_Should_ReturnNoContent() {
    //Arrange
    ToDoList existingItem =  GenerateRandomItem();
    var itemID = existingItem.Id;
    
    Mock<IToDoListRepository> repositoryStub = new ();
    
    //Setup expected behavior of mock
    repositoryStub
        .Setup(_ => _.GetSpecificTodoAsync(itemID))
        .ReturnsAsync(existingItem);
    repositoryStub.Setup(_ => _.SaveChangesAsync()).ReturnsAsynt(true);
    
    var controller = new ToDoController(repositoryStub.Object, mapper.Object);
    
    //Act
    ActionResult result = await controller.DeleteToDoList(itemID);

    //assert
    result.Should().BeOfType<NoContentResult>();
}
  • Related