单位测试带有实体框架核心1.1.2的存储的Proc



我有一种使用实体框架调用存储proc的方法,存储的proc返回了一些数据。

类似以下的东西

public async Task<IActionResult> Get(int customerId)
{
   List<Product> products = _context.Products.FromSql("EXECUTE dbo.SpGatherProductInfo {0}", customerId)
        .ToList();
   if (!products.Any())
   {
      return NotFound();
   }
   return Ok(products);
}

如果这是对表的简单查询,我会创建一个内存DB,添加一些假条目,一切都很好。

但这使用了存储的Proc,我如何单元测试?

您过多地关注实施问题。在这种情况下,实体框架是一个实施问题。

这看起来像是将关注点封装到抽象中的好情况。

public interface IProductService  {
    Task<List<Product>> GatherProductInfo(int customerId);
}

并将其注入控制器

public class ProductsController : Controller {
    private readonly IProductService service;
    public ProductsController(IProductService service) {
        this.service = service;
    }
    public async Task<IActionResult> Get(int customerId) {
        List<Product> products = await service.GatherProductInfo(customerId);
        if (!products.Any()) {
            return NotFound();
        }
        return Ok(products);
    }
}

IProductService实现将取决于上下文和实际存储过程执行,而控制器仅取决于抽象。控制器不应关心数据的来源。

现在,这允许控制器在隔离中测试 ,而无需紧密耦合到实现问题类似于实体框架。

public async Task Product_Not_Found() {
    //Arrange
    var customerId = 1;
    var products = new List<Product>();// Currently empty but could easily
                                       //  be populated for another test.
    var mock = new Mock<IProductService>();
    mock.Setup(_ => _.GatherProductInfo(customerId)).Returns(products);
    var controller = new ProductsController(mock.Object);
    //Act
    var result = await controller.Get(customerId);
    //Assert
    result.Should().NotBeNull()
        .And.BeTypeOf<NotFoundResult>();
}

我的一位同事弄清楚了如何模拟存储的Proc调用。

然后我只在测试中使用该模拟。

我在这里写了一篇详细的博客文章,有很多代码,所以我不仅复制博客中的所有内容 -

https://nodogmablog.bryanhogan.net/2017/11/unit-testing-entity-framework-core-core-stored-procedures/

最新更新