嘲笑在C#中使用Moq

我有以下代码:

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<IProductDataAccess>对象对其进行初始化,但将数据访问暴露给UI层不是一个好习惯。 谁能帮我?


经典示例,显示如果您无法单元测试某个特定组件,则使用REFACTOR组件!

这就是任何模拟框架强制要求你去做的地方 - 编写解耦代码。

在您的示例中, ProductBusiness类与ProductDataAccess紧密结合。 你可以使用(如大多数答案所建议的)依赖注入来解耦它。 通过这样做,您最终将取决于IProductDataAccess抽象,而不是其任何具体实现。

另一点需要注意的是,在编写业务层的测试/规范时,通常需要测试“行为”而不是“状态”。 因此,虽然您可以断言验证返回“true”,但您的测试应真正测试是否使用MOQ的“.Verify”API实际执行的MOQ设置的预期数据访问调用。

尝试添加行为测试,您希望数据访问层引发异常(使用“.Throws”API),并检查是否需要在业务层进行任何特殊处理。

像凯文建议的那样,让ProductBusiness看起来像这样:

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测试框架将测试编写为:

 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

您应该将IProductDataAccess接口注入为依赖项:

public class ProductBusiness
{
    private IProductDataAccess _productDataAccess;    

    public ProductBusiness(IProductDataAccess productDataAccess)
    {
        _productDataAccess = productDataAccess;
    }

    public bool CreateProduct(Product newProduct)
    {
        bool result = _productDataAccess.CreateProduct(newProduct);
        return result;
    }
}

然后你可以在测试中用模拟替换它:

var productDataAccess = new Mock<IProductDataAccess>();
var productBusiness = new ProductBusiness(productDataAccess.Object);

通过您目前设计ProductBusiness类的方式, IProductDataAccess使用模拟来更改IProductDataAccess实现。 对此的推荐模式是依赖注入,其中通过构造函数获取类型的依赖关系。 所以你的班级变成:

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;
  }
}

现在你可以通过使用像moq这样的模拟框架来测试你的类。 例如:

var mockDataAccess = new Mock<IProductDataAccess>();
mockDataAccess
    .Setup(m => m.CreateProduct(It.IsAny<Product>()))
    .Returns(true);

var productBusiness = new ProductBusiness(mockDataAccess.Object);
// ... test behaviour here

现在,您可以更改模拟在设置步骤中的行为方式,并确保您的CreateProduct方法的行为正确。

我也会看看像castle-windsor这样的依赖注入框架。 依赖注入框架可以自动解决依赖关系,这意味着创建新类型会更容易,因为您不必手动创建新的一切。 此外,它意味着您可以更改在一个地方使用哪个实现,并且它随处可见。

链接地址: http://www.djcxy.com/p/54061.html

上一篇: Mocking using Moq in c#

下一篇: Mocking classes that implement IQueryable with Moq