如何对依赖于Factory的代码进行单元测试

时间:2017-09-26 14:10:16

标签: c# unit-testing factory

我有一个DataService类,如下所示

public class LessonDataService
{

    IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork();

    public Lesson FindById(int id)
    {
        try
        {
            return unitOfWork.Lessons.FindById(id);
        }
        catch (Exception ex)
        {
            throw exception;
        }
    }
}

正如您所看到的,UnitOfWork是在DataService类中构造的。我也不希望通过构造函数传递UnitOfWork,我不希望UI代码打扰UnitOfWork我只是想让它调用DataService类并让它完成剩下的工作。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

  

如何对依赖于工厂的代码进行单元测试

简答:你不

Abstract Factories are a code smell

紧密耦合的代码很难测试。 (但并非不可能)。

通过构造函数注入重构代码以显式依赖。 (避免服务定位器反模式)

public class LessonDataService : ILessonDataService {    
    private readonly IUnitOfWork unitOfWork;

    public LessonDataService(IUnitOfWork unitOfWork) {
        this.unitOfWork = unitOfWork;
    }

    public Lesson FindById(int id) {
        try {
            return unitOfWork.Lessons.FindById(id);
        } catch (Exception ex) {
            throw exception;
        }
    }
}
  

我不希望UI代码烦扰UnitOfWork我只是希望它调用DataService类并让它完成剩下的工作。

然后抽象服务,将其注入UI并让其完成剩下的工作。用户界面不应直接与UOW有关。

public interface ILessonDataService  {
    Lesson FindById(int id);
}

通过重构依赖于显式抽象,代码现在更加灵活,可以在最小的负面影响下进行单独测试。

[TestMethod]
public void DataService_Should_Get_Lesson() {
    //Arrange
    var id = 1;
    var lesson = new Lesson {
        Id = id,
        //...code removed for brevity
    };
    var mock = new Mock<IUnitOfWork>();
    mock.Setup(_ => _.Lessons.FindById(id)).Returns(lesson);

    var sut = new LessonDataService(mock.Object);

    //Act
    var actual = sut.FindById(id);

    //Assert
    lession.Should().BeEquivalentTo(actual);
}

在生产代码中,当前工厂仍然可以在组合根中注册DI容器,但仍然可以使代码解耦。

例如(在.Net Core中)

services.AddTransient<IUnitOfWork>(_ => UnitOfWorkFactory.CreateUnitOfWork());
services.AddTransient<ILessonDataService, LessonDataService>();

答案 1 :(得分:0)

使用Mocking框架。单元测试用于测试代码段而不是分支或连接类。使用像Mockito或easymock这样的模拟框架,模拟UnitOfWorkFactory并为unitOfWork.Lessons.FindById(id)创建自己的输出。记得测试所有可能性。使用此link了解有关Mockito的更多信息。

答案 2 :(得分:0)

我解决的问题是我为DataService创建了一个内部构造函数,并使用InternalsVisibleToAttribute使单元测试项目可见,以便我可以覆盖工厂和注入和模拟UnitOfWork。