如何在 .NET for web 中编写单元测试 api

How can I write unit Tests in .NET for web api

我的删除方法控制器:

[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();

    }

我的存储库:

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);
    }

我的测试用例,用于检查项目是否被删除以及是否 returns 删除后没有内容。但是我的两个测试用例都失败了。任何有关如何为删除部分编写测试用例的帮助,我将不胜感激。我也在尝试测试其他方法,但不幸的是我被困在这里。请帮助我

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>();

        }

两个测试用例都失败了,因为模拟没有设置为每个测试用例都按预期运行。

显示的测试中也存在潜在的竞争条件,因为它们共享同一个模拟实例。这将在设置模拟时引起问题,因为一个测试用例可能会覆盖另一个用例的设置。

更新测试,使它们相互隔离。

在第一个测试中,可以通过检查模拟以查看是否调用了预期的成员来验证预期的行为。

[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));
}

在另一个测试中,需要设置模拟以确保主题执行到完成。

[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>();
}