模拟ApiController

时间:2016-07-13 14:38:44

标签: c# asp.net-web-api nunit moq

我正在尝试测试我制作的WebApi控制器。我试图使用依赖注入来使测试更容易。虽然它实际上有相反的效果。

我目前有一个控制器在其构造函数中使用repo接口。 repo接口也在其构造函数中使用DbContext接口。我是否正确地认为我需要模拟DbContext,并在模拟repo时将该模拟的上下文作为参数传递,然后将该模拟的repo传递给我正在测试的控制器的实际实现?

我正在使用Moq和NUnit。

由于

2 个答案:

答案 0 :(得分:4)

我假设您正在谈论单元测试,因为您正在使用模拟。

您不需要比第一级接口更深入地模拟您单元测试所依赖的类。在您的示例中,您的controller取决于让我们调用IRepository的界面。您IRepository 实施 依次收录IDbContext。请注意上一句中的粗体/斜体,只要您模拟IRepository的界面,然后IDbContext与之无关 - IDbContext是依赖关系您的具体存储库,但不是您的IRepository

您的IRepository应该拥有控制器所需的一切,用于模拟与控制器单元测试相关的数据/行为。

示例:

public class MyController : MyController
{
    private readonly IRepository _repo;

    public MyController(IRepository repo)
    {
        _repo = repo;
    }

    public IActionResult GetData(string userId)
    {
        var data = _repo.GetUserInformation(userId);
        var someTransformation = null; // transform data
        return View(someTransformation);
    }
}

public interface IRepository
{
    MyObject GetData(string userId);
}

public class Repository : IRepository
{
    private readonly IDbContext _iDbContext;

    public Repository(IDbContext iDbContext)
    {
        _iDbContext = iDbContext;
    }

    public MyObject GetUserInformation(string userId)
    {
        return _iDbContext.MyObjects.Where(w => w.UserId == userId);
    }
}

public interface IDbContext
{
    // impl
}

public class DbContext : IDbContext
{
    // impl
}

出于测试MyController的目的,您依赖于接口IRepository。反过来,IRepositoryRepository)的实施依赖于什么,因为这与测试MyController的范围无关。

在你的测试中:

public class MyControllerTests
{
    public void MyTest()
    {
        Mock<IRepository> mockRepo = new Mock<IRepository>();
        mockRepo
            .Setup(s => s.GetUserInformation(It.IsAny<string>())
            .Returns(new MyObject()
            {
                UserId = "whatever", // or whatever the mocked data needs to be
                DateCreated = DateTime.MinValue
            });
    }
}

在上面的测试中,我们提供了IRepository在调用GetUserInformation时应返回的示例数据,我们不依赖于实际DbContextIDbContext甚至,因为IRepository只是定义了一个&#34;当用字符串调用GetUserInformation时,它应该返回一个MyObject&#34;。如何做到这一点并不重要。

答案 1 :(得分:1)

相信你的直觉。我假设您的DbContext实现了一个接口,使您可以访问所需的一切,并且该接口是通过DI传递到控制器构造函数的接口。

在测试程序集中,创建一个实现接口的MockDbContext并返回已知的模拟数据。然后使用MockDbContext创建控制器的实例,并对控制器运行测试。

如果您有任何问题,请发表评论,我会尝试通过更新答案来提供帮助。