且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用 XUnit 对 Web API 控制器进行单元测试

更新时间:2023-02-17 13:25:02

在进行测试之前,我建议您在代码中更新一些内容:

Before going to testing, there are a few things I recommend updating in your code:

  • 使您的存储库方法和控制器操作异步(因此 Web 服务器可以在等待先前调用的数据库往返时处理请求)
  • 使用 ActionResult 作为动作返回类型.通过这种方式,您可以向客户端发送不同的 http 状态代码.
  • 未找到标题时返回 404 NotFound 状态代码,而不是返回以 null 作为负载的成功结果.
  • 考虑对 API 端点使用 RESTful 方法.例如.titles 资源的基本 uri 应该类似于 api/titles
  • 不要指定 getTitle 来获取标题端点,因为您知道 HTTP 动词将哪个端点映射到 (GET) 和基本资源 url (api/titles).
  • Make your repository methods and controller actions async (thus web server can process requests while waiting for database roundtrips for previous calls)
  • Use ActionResult as an action return type. This way you can send different http status codes to the client.
  • Return 404 NotFound status code when title not found instead of returning successful result with null as payload.
  • Consider using a RESTful approach for API endpoints. E.g. base uri for titles resource should be something like api/titles
  • Don't specify getTitle for getting title endpoint, because you know HTTP verb which endpoint is mapped to (GET) and base resource url (api/titles).

应用这些注释:

[ApiController]
[Route("api/titles")]
public class TitleController : Controller
{
    private IGtlTitleRepository _gtlTitleRepository;

    public TitleController(IGtlTitleRepository gtlTitleRepository)
    {
        _gtlTitleRepository = gtlTitleRepository;
    }

    [HttpGet("{ISBN}")] // GET api/titles/{ISBN}
    public async Task<ActionResult<GtlTitle>> GetTitle(string ISBN)    
    {
        var title = await _gtlTitleRepository.GetTitle(ISBN);
        if (title == null)
            return NotFound();

        return title;
    }
}

测试标题检索成功:

[Fact]
public async Task Should_Return_Title_When_Title_Found()
{
    var repositoryMock = new Mock<IGtlTitleRepository>();
    var title = new GtlTitle();
    repositoryMock.Setup(r => r.Get("978-0-10074-5")).Returns(Task.FromResult(title));

    var controller = new TitleController(repositoryMock.Object);

    var result = await controller.GetTitle("978-0-10074-5");
    Assert.Equal(title, result.Value);
}

未找到标题时:

[Fact]
public async Task Should_Return_404_When_Title_Not_Found()
{
    var repositoryMock = new Mock<IGtlTitleRepository>();
    repositoryMock.Setup(r => r.Get("978-0-10074-5")).Returns(Task.FromResult<GtlTitle>(null));

    var controller = new TitleController(repositoryMock.Object);

    var result = await controller.GetTitle("978-0-10074-5");
    Assert.IsType<NotFoundResult>(result.Result);
}