在 .net Core 中使用通用存储库进行单元测试
Unit testing with Generic Repository in .net Core
我正在围绕 .net 核心构建一个 fiddle 的测试项目,但遇到了某种障碍。玩弄的基本思想是将产品添加到上下文中,这没什么大不了的。错了。因为我是作为一名优秀的程序员长大的,所以我总是从 TDD 开始。所以我尝试了以下测试。
[Fact]
public async Task AddProduct_ReturnCreatedWithProduct()
{
Product testProduct = ProductHelpers.GenerateTestProduct();
var mockRepo = new Mock<IRepository<Product>>();
mockRepo.Setup(repo => repo.Get(testProduct.ProductID)).Returns(Task.FromResult(testProduct));
var controller = new ProductController(mockRepo.Object);
var result = await controller.Post(new ProductViewModel() { ProductID = 1, ProductShortDesc = PRODUCT_SHORTDESC, ProductDescription = PRODUCT_DESC });
var okResult = Assert.IsType<OkObjectResult>(result);
var returnProduct = Assert.IsType<Product>(okResult.Value);
Assert.Equal(testProduct.ProductShortDesc, returnProduct.ProductShortDesc);
Assert.Equal(testProduct.ProductDescription, returnProduct.ProductDescription);
}
public static Product GenerateTestProduct()
{
return new Product()
{
ProductID = 1,
ProductShortDesc = "FRI",
ProductDescription = "Fristi"
};
}
哪个应该return一个像样的OkObjectResult
。好吧,不,它没有。所以我深入研究了给了我这个的控制器。
[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
else
{
var product = await _productRepository.AddEntity(model.ToEntity());
if (product == null)
return StatusCode(500);
else
return Ok(product);
}
}
public interface IRepository<T>
{
Task<T> Get<TKey>(TKey id);
IQueryable<T> GetAll();
Task<T> AddEntity(T entity);
Task DeleteEntity(T entity);
Task Update(T entity);
}
public class ProductRepository : IRepository<Product>
{
protected readonly DbContext Context;
protected DbSet<Product> DbSet;
public ProductRepository(ApplicationContext context)
{
Context = context;
DbSet = context.Set<Product>();
}
public async Task<Product> AddEntity(Product entity)
{
try
{
await Context.Set<Product>().AddAsync(entity);
await Save();
return await Get(entity.ProductID);
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
throw ex;
}
}
//Rest left out for shortness off this post
}
所以 运行 通过邮递员的代码给了我以下结果:
所以回到测试因为我想,是的,它现在以某种方式起作用了..
[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
else
{
var product = await _productRepository.AddEntity(model.ToEntity());
if (product == null)
return StatusCode(500);
else
return Ok(product);
}
}
所以那也不顺利。我尝试调试代码以找到根本原因,但出于某种原因,它不允许我在接口代码中逐步执行以找出为什么 Add 在我的单元测试中不起作用,但在正常的邮递员测试中起作用。 (仅我的代码被禁用)。希望你们中的一些人可以帮助我解决这个问题
测试模拟了错误的方法。被测方法仅与 AddEntity
交互,因此这是该测试应模拟的依赖项。
mockRepo
.Setup(repo => repo.AddEntity(It.Is<Product>(vm =>
vm.ProductShortDesc == testProduct.ProductShortDesc
&& vm.ProductDescription == testProduct.ProductDescription)
)
)
.ReturnsAsync(testProduct);
其他一切都可以保持不变。
我正在围绕 .net 核心构建一个 fiddle 的测试项目,但遇到了某种障碍。玩弄的基本思想是将产品添加到上下文中,这没什么大不了的。错了。因为我是作为一名优秀的程序员长大的,所以我总是从 TDD 开始。所以我尝试了以下测试。
[Fact]
public async Task AddProduct_ReturnCreatedWithProduct()
{
Product testProduct = ProductHelpers.GenerateTestProduct();
var mockRepo = new Mock<IRepository<Product>>();
mockRepo.Setup(repo => repo.Get(testProduct.ProductID)).Returns(Task.FromResult(testProduct));
var controller = new ProductController(mockRepo.Object);
var result = await controller.Post(new ProductViewModel() { ProductID = 1, ProductShortDesc = PRODUCT_SHORTDESC, ProductDescription = PRODUCT_DESC });
var okResult = Assert.IsType<OkObjectResult>(result);
var returnProduct = Assert.IsType<Product>(okResult.Value);
Assert.Equal(testProduct.ProductShortDesc, returnProduct.ProductShortDesc);
Assert.Equal(testProduct.ProductDescription, returnProduct.ProductDescription);
}
public static Product GenerateTestProduct()
{
return new Product()
{
ProductID = 1,
ProductShortDesc = "FRI",
ProductDescription = "Fristi"
};
}
哪个应该return一个像样的OkObjectResult
。好吧,不,它没有。所以我深入研究了给了我这个的控制器。
[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
else
{
var product = await _productRepository.AddEntity(model.ToEntity());
if (product == null)
return StatusCode(500);
else
return Ok(product);
}
}
public interface IRepository<T>
{
Task<T> Get<TKey>(TKey id);
IQueryable<T> GetAll();
Task<T> AddEntity(T entity);
Task DeleteEntity(T entity);
Task Update(T entity);
}
public class ProductRepository : IRepository<Product>
{
protected readonly DbContext Context;
protected DbSet<Product> DbSet;
public ProductRepository(ApplicationContext context)
{
Context = context;
DbSet = context.Set<Product>();
}
public async Task<Product> AddEntity(Product entity)
{
try
{
await Context.Set<Product>().AddAsync(entity);
await Save();
return await Get(entity.ProductID);
}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
throw ex;
}
}
//Rest left out for shortness off this post
}
所以 运行 通过邮递员的代码给了我以下结果:
所以回到测试因为我想,是的,它现在以某种方式起作用了..
[HttpPost]
public async Task<ActionResult> Post([FromBody]ProductViewModel model)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
else
{
var product = await _productRepository.AddEntity(model.ToEntity());
if (product == null)
return StatusCode(500);
else
return Ok(product);
}
}
所以那也不顺利。我尝试调试代码以找到根本原因,但出于某种原因,它不允许我在接口代码中逐步执行以找出为什么 Add 在我的单元测试中不起作用,但在正常的邮递员测试中起作用。 (仅我的代码被禁用)。希望你们中的一些人可以帮助我解决这个问题
测试模拟了错误的方法。被测方法仅与 AddEntity
交互,因此这是该测试应模拟的依赖项。
mockRepo
.Setup(repo => repo.AddEntity(It.Is<Product>(vm =>
vm.ProductShortDesc == testProduct.ProductShortDesc
&& vm.ProductDescription == testProduct.ProductDescription)
)
)
.ReturnsAsync(testProduct);
其他一切都可以保持不变。