我已經嘗試了幾天來測驗洗掉方法,但沒有成功。
除錯代碼后,我意識到問題在于FindAsync 方法回傳 null,這導致測驗落入NotFound()條件。
由于我是 C#、.NET、EntityFramework 和 Moq 世界的新手,任何人都可以幫助我嗎?
- 控制器
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
- 測驗
[Fact]
public async Task DeleteTodoItem_ShouldBeCallFindAsyncMethodOnce()
{
var todo = new TodoItem { Id = 1, Name = "test", IsComplete = true };
var mockSet = new Mock<DbSet<TodoItem>>();
var options = new DbContextOptionsBuilder<TodoContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var mockContext = new Mock<TodoContext>(options);
mockContext.Setup(c => c.TodoItems).Returns(mockSet.Object);
mockContext.Setup(c => c.TodoItems.FindAsync(1)).ReturnsAsync(todo);
var service = new TodoItemsController(mockContext.Object);
var deleteTodo = await service.DeleteTodoItem(1);
mockSet.Verify(m => m.FindAsync(It.IsAny<TodoItem>()), Times.Once());
}
uj5u.com熱心網友回復:
當您的控制器長時間傳遞它時,您正在為 int 上的 FindAsync 設定一個模擬并驗證模擬。因此,您需要在 long 而不是 int 中設定模擬和驗證。并且還在 DbSet 上設定 FindAsync 模擬,而不是在 DbContext 上。
例如:
var todo = new TodoItem { Id = 1, Name = "test", IsComplete = true };
var mockSet = new Mock<DbSet<TodoItem>>();
mockSet.Setup(s => s.FindAsync(1L)).ReturnsAsync(todo);
var mockContext = new Mock<TodoContext>();
mockContext.Setup(c => c.TodoItems).Returns(mockSet.Object);
var service = new TodoItemsController(mockContext.Object);
var deleteTodo = await service.DeleteTodoItem(1);
mockSet.Verify(m => m.FindAsync(1L), Times.Once());
在這里完成作業示例。用于驗證的完整代碼如下。
// Need package reference to Microsoft.EntityFrameworkCore v6.0.5
// Need package reference to Moq v4.18.1
using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Moq;
public class Program
{
public static async Task Main()
{
var todo = new TodoItem { Id = 1, Name = "test", IsComplete = true };
var mockSet = new Mock<DbSet<TodoItem>>();
mockSet.Setup(s => s.FindAsync(1L)).ReturnsAsync(todo);
var mockContext = new Mock<TodoContext>();
mockContext.Setup(c => c.TodoItems).Returns(mockSet.Object);
var service = new TodoItemsController(mockContext.Object);
var deleteTodo = await service.DeleteTodoItem(1);
mockSet.Verify(m => m.FindAsync(1L), Times.Once());
Console.WriteLine("Test complete without error");
}
}
public class TodoContext : DbContext
{
public virtual DbSet<TodoItem> TodoItems { get; set; }
}
public class TodoItem
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
public class TodoItemsController
{
readonly TodoContext _context;
public TodoItemsController(TodoContext context)
{
_context = context;
}
public async Task<IActionResult> DeleteTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);
if (todoItem == null)
{
return NotFound();
}
_context.TodoItems.Remove(todoItem);
await _context.SaveChangesAsync();
return NoContent();
}
public NotFoundResult NotFound() { return new NotFoundResult(); }
public NoContentResult NoContent() { return new NoContentResult(); }
}
public interface IActionResult{}
public class NotFoundResult : IActionResult {}
public class NoContentResult : IActionResult {}
請注意,此測驗似乎不是特別有用。通常在單元測驗時,我們圍繞結果進行斷言,而不是圍繞實作細節進行斷言。無需斷言 FindAsync 被呼叫過一次。它只會使測驗更加脆弱。如果您正在對 action 方法進行單元測驗,您需要確保在傳入不存在的專案時獲得 NotFoundResult,在傳入現有專案時獲得 NoContentResult,并且正確的專案被洗掉來自 DbSet。使用記憶體中的 DbContext 而不是模擬它可能會更簡單。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/476740.html
下一篇:打破嵌套回圈
