我有一个使用Entity Framework来调用存储过程的方法,存储的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);
}
如果这是对表的简单查询,我会创建一个内存数据库,添加一些假的条目,一切都会好的。
但是这使用了存储过程,我该如何对它进行单元测试?
答案 0 :(得分:0)
您过分关注实施问题。在这种情况下,实体框架是一个实现问题。
这似乎是将这种关注封装到抽象中的好例子。
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>();
}
答案 1 :(得分:0)
我的一位同事想出了如何模拟存储的proc调用。
然后我只是在测试中使用那个模拟。
我在这里写了一篇关于它的详细博客文章,有很多代码所以我不会只是从博客中复制粘贴一切 -