Unit Testing BLL: mock Repository, UnitOfWork, UnitOfWorkFactory

删除回忆录丶 提交于 2019-12-13 02:58:32

问题


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

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

  1. Mock the repositories Add method.
  2. Mock the UoW Materials property to return my repository mock.
  3. Mock the UoWFactory to return the UoW mock.
  4. Create the MaterialsBLL giving the mocked UoWFactory to the contstructor.
  5. Verify that the AddNewMaterials calls the repository's Add, and the UoW's Save, etc.

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

回答1:


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

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

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.



来源:https://stackoverflow.com/questions/23534123/unit-testing-bll-mock-repository-unitofwork-unitofworkfactory

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!