单元测试 BLL:模拟存储库、UnitOfWork、UnitOfWorkFactory [英] Unit Testing BLL: mock Repository, UnitOfWork, UnitOfWorkFactory

查看:50
本文介绍了单元测试 BLL:模拟存储库、UnitOfWork、UnitOfWorkFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要快速开始测试业务层上的方法.考虑 Materials BLL 对象,我该如何测试它的 AddNewMaterial 方法?

I need a jump start in testing the methods on my Business layer. Consider the Materials BLL object, how can I test the AddNewMaterial method for it?

interface IGenericRepository<TEntity>
{
    TEntity Add(TEntity m); 
}

public interface IMaterialRepository : IGenericRepository<Material>
{
}

public interface IUnitOfWork
{
    IMaterialRepository Materials { get; private set;}

    void Save();
}

public interface IUnitOfWorkFactory
{
    IUnitOfWork GetUnitOfWOrk();
}

public class MaterialsBLL
{
    private readonly IUnitOfWorkFactory _uowFactory;

    //uowFactory comes from DI
    public MaterialsBLL(IUnitOfWorkFactory uowFactory)
    {
        _uowFactory = uowFactory;
    }

    //TODO: test this
    public Material AddNewMaterial(Material m)
    {
        using(var uow = _uowFactory.GetUnitOfWOrk())
        {
            var result = uow.Materials.Add(m);
            uow.Save();
            return result;
        }
    }

我正在使用 Moq 和 XUnit,但非常环保.一般来说,我想这样做:

I am using Moq, and XUnit, but am very green. In general I want to do this:

  1. 模拟存储库的 Add 方法.
  2. 模拟 UoW Materials 属性以返回我的存储库模拟.
  3. 模拟 UoWFactory 以返回 UoW 模拟.
  4. 创建 MaterialsBLL,将模拟的 UoWFactory 提供给构造函数.
  5. 验证 AddNewMaterials 调用存储库的 Add 和 UoW 的 Save 等.

在我看来,我可能应该创建一个 Fake MaterialRepository,而不是嘲笑它?还有什么建议吗?这是第一次破解:

It seems to me that, I maybe should be creating a Fake MaterialRepository, rather than mocking it? Any other advice? Here is a first crack:

    [Fact]
    public void TestGetMaterialById()
    {
        var materialList = GetMaterials();

        var materialRepositoryMock = new Mock<IMaterialRepository>();
        materialRepositoryMock.Setup(repo => repo.Get(4)).Returns(materialList.First());

        var uowMock = new Mock<IUnitOfWork>();
        uowMock.SetupProperty<IMaterialRepository>(uow => uow.Materials, materialRepositoryMock.Object);

        var uowFactoryMock = new Mock<IUnitOfWorkFactory>();
        uowFactoryMock.Setup(f => f.GetUnitOfWork()).Returns(uowMock.Object);

        var materialsBll = new Materials(uowFactoryMock.Object);
        var result = materialsBll.Get(4);

        Assert.Equal(result.MaterialId, 4);
        Assert.Equal(result.Name, "Four");
    }

推荐答案

当您觉得需要多层嵌套模拟对象时,通常是您的设计出了问题.

When you feel like you need several levels of nested mock objects, there's generally something wrong with your design.

德米特法则在此警告我们,您可能不应该修改 uow.MaterialsMaterialsBLL 中.

The Law of Demeter warns us here that you should probably not tinker with uow.Materials in MaterialsBLL.

此外,工作单元通常不是公开存储库的地方.需要访问 Materials 的代码通常会直接引用 IMaterialsRepository,而不是从 UoW 请求它,然后 Repository 实现可能会在内部引用 UoW.

Besides, a Unit of Work is typically not the place to expose Repositories. The code that needs to access Materials will usually have a direct reference to an IMaterialsRepository, not ask it from the UoW, and then the Repository implementation might reference the UoW internally.

这会导致更扁平的设计并简化您的生产代码和测试.

This leads to a flatter design and simplifies your production code as well as your tests.

这篇关于单元测试 BLL:模拟存储库、UnitOfWork、UnitOfWorkFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆