问题描述
我有以下代码:
public interface IProductDataAccess
{
bool CreateProduct(Product newProduct);
}
类 ProductDataAccess
实现该接口.
public class ProductBusiness
{
public bool CreateProduct(Product newProduct)
{
IProductDataAccess pda = new ProductDataAccess();
bool result = pda.CreateProduct(newProduct);
return result;
}
}
在这种情况下,如何通过模拟 IProductDataAccess
接口为 CreateProduct
方法创建单元测试?我想在 ProductBusiness
中有一个 IProductDataAccess
的公共实例并使用 Mock
对象对其进行初始化,但公开它不是一个好习惯对 UI 层的数据访问.谁能帮帮我?
In this case, how to create unit test for CreateProduct
method by mocking the IProductDataAccess
interface? I thought of having an public instance of IProductDataAccess
within ProductBusiness
and initialize it using Mock<IProductDataAccess>
object but it is not a good practice to expose the data access to the UI layer. Can any one help me?
推荐答案
经典示例演示如果您无法对特定组件进行单元测试,请对其进行重构!
Classic example which demonstrates that if you cannot unit test a particular component, REFACTOR it!
这就是为什么我喜欢任何模拟框架强制您执行的操作 - 编写解耦代码.
This is why I love what any mocking framework enforces you to do - write decoupled code.
在您的示例中,ProductBusiness
类与 ProductDataAccess
类紧密耦合.您可以使用(就像大多数答案建议的那样)依赖注入来解耦它.通过这样做,您最终将依赖于 IProductDataAccess
抽象,而不是依赖于它的任何具体实现.
In your example, the ProductBusiness
class is tightly coupled with the ProductDataAccess
class. You could decouple it using (like most of the answers suggest) dependency injection. By doing so, you would end up depending on the IProductDataAccess
abstraction and not on any concrete implementation of it.
还有一点需要注意,当您为业务层编写测试/规范时,您通常希望测试行为"而不是状态".因此,尽管您可以断言验证是否返回true",但您的测试应该真正测试使用 MOQ 设置的预期数据访问调用是否实际使用 MOQ 的 .Verify
API 执行.
Another point to note, when you are writing tests/specifications for the business layer, you would typically want to test the "behavior" and not the "state". So, although you could have asserts that verify if "true" was returned, your tests should really test if the expected data access calls that were set using MOQ were actually executed using the .Verify
API of MOQ.
尝试在您希望数据访问层抛出异常(使用.Throws"API)的地方添加行为测试,并检查您是否需要在业务层进行任何特殊处理.
Try adding behavior tests where you expect an exception to be thrown (using the ".Throws" API) by the data access layer and check if you need any special handling at the business layer.
就像 Kevin 建议的那样,ProductBusiness
的以下实现将起作用:
Like Kevin suggests, the following implementation of ProductBusiness
will work:
public class ProductBusiness
{
private readonly IProductDataAccess _productDataAccess;
public ProductBusiness(IProductDataAccess productDataAccess)
{
_productDataAccess = productDataAccess;
}
public bool CreateProduct(Product newProduct)
{
bool result=_productDataAccess.CreateProduct(newProduct);
return result;
}
}
并使用任何 xunit 测试框架将测试编写为:
and use any xunit testing framework to write the test as:
var mockDataAccess = new Mock<IProductDataAccess>();
mockDataAccess.Setup(m => m.CreateProduct(It.IsAny<Product>())).Returns(true);
var productBusiness = new ProductBusiness(mockDataAccess.Object);
//behavior to be tested
这篇关于在 c# 中使用 Moq 进行模拟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!