0

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

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,但我很环保。一般来说,我想这样做:

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

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

    [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");
    }
4

1 回答 1

0

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

墨忒耳法则在这里警告我们,你可能不应该uow.MaterialsMaterialsBLL

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

这会带来更扁平的设计并简化您的生产代码和测试。

于 2014-05-08T12:14:58.063 回答