c# - 如何使用 XUnit 对 Web API Controller 进行单元测试

标签 c# unit-testing xunit webapi

我正在尝试使用 XUnit 在我的 Web API 中的 Controller 中对方法进行单元测试。该方法的作用是根据 ISBN 从数据库中获取单个书名。我在单元测试期间遇到的问题是我不确定如何插入我必须对其执行测试的虚拟数据,以及 Assert 函数如何工作。

TitleController.cs

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

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

    [Route("getTitle/{ISBN}")]
    [HttpGet()]
    public GtlTitle GetTitle(string ISBN)    
    {
        return _gtlTitleRepository.GetTitle(ISBN);
    }
}

IGtlTitleRepository.cs

    public interface IGtlTitleRepository
{
    GtlTitle GetTitle(string ISBN);
}

MockGtlTitleRepository.cs

    public class MockGtlTitleRepository : IGtlTitleRepository
{
    private readonly string _connection;
    public MockGtlTitleRepository(IOptions<ConnectionStringList> connectionStrings)
    {
        _connection = connectionStrings.Value.GTLDatabase;
    }


    private List<GtlTitle> _titleList;

    public GtlTitle GetTitle(string ISBN)
    {
        using (var connection = new SqlConnection(_connection))
        {
            connection.Open();
            return connection.QuerySingle<GtlTitle>("GetTitleByISBN", new { ISBN }, commandType: CommandType.StoredProcedure);
        }
    }

}

是的,至于我的测试代码,我可以写出下面的代码,但是正如我上面所说的,我想不出一个合适的方法来测试这个方法。

 public class UnitTest1
{
    [Fact]
    public void Test1()
    {

        var repositoryMock = new Mock<IGtlTitleRepository>();
        var title = new GtlTitle();
        repositoryMock.Setup(r => r.GetTitle("978-0-10074-5")).Returns(title);
        var controller = new TitleController(repositoryMock.Object);

        var result = controller.GetTitle("978-0-10074-5");
       // assert??
        repositoryMock.VerifyAll();
    }
}

为了正确测试该方法,应该在此单元测试中完成什么?

编辑:

GtlTitle.cs

public class GtlTitle
{
    public string ISBN { get; set; }
    public string VolumeName { get; set; }
    public string TitleDescription { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PublisherName { get; set; }

}

最佳答案

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

  • 使您的存储库方法和 Controller 操作异步(因此网络服务器可以在等待数据库往返以进行先前调用的同时处理请求)
  • 使用ActionResult 作为 Action 返回类型。这样您就可以向客户端发送不同的 http 状态代码。
  • 当找不到标题时返回 404 NotFound 状态代码,而不是返回以 null 作为有效负载的成功结果。
  • 考虑对 API 端点使用 RESTful 方法。例如。标题资源的基本 uri 应该类似于 api/titles
  • 不要指定 getTitle 来获取标题端点,因为您知道映射到哪个端点的 HTTP 动词 (GET) 和基本资源 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);
}

关于c# - 如何使用 XUnit 对 Web API Controller 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61999456/

相关文章:

c# - 如何指向不同环境的 Entity Framework 数据库上下文

c# - 作为 WebService 使用的 WCF 添加了一个 bool 参数?

swift - 表达式类型 '()' 在没有更多 XCTAssertEqual 上下文的情况下不明确

java - Junit - 比较两个 XML 文档是否相同

c# - 在单元测试中方法执行后设置变量名称

c# - web.config、web.config.debug、web.config.release有什么用?

c# - 如何调试 Azure EventHub?

unit-testing - 如何测试 Angular2 的 router.navigate?

unit-testing - 使用 jasmine 进行 Angular 2 可观察错误测试

c# - 单元测试中的进度指示