嘲笑 API 控制器

本文关键字:控制器 API 嘲笑 | 更新日期: 2023-09-27 17:56:42

我正在尝试测试我制作的WebApi控制器。我尝试使用依赖注入来简化测试。尽管它实际上具有相反的效果。

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

我正在使用最小起订量和 NUnit。

谢谢

嘲笑 API 控制器

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

你不需要模拟比

你正在单元测试的类所依赖的第一级接口更深的模拟。 在您的示例中,您的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
            });
    }
}

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

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

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

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