一次性方法的单元测试

时间:2016-04-14 22:24:57

标签: c# unit-testing

我的单元测试有问题。 我有一个标准的Reprository和UnitOfWork模式。 例如,我有一个UnitOfWork类:

public class UnitOfWork : IDisposable
{
    private readonly MyDbContext _context;

    ... repositories 
    private IMyEntityRepository _myEntityRepository;
    ...
}

UnitOfWok用于程序的另一部分,它与实体进行一些特殊操作。例如,有一种方法,使用UnitOfWork:

public IEnumerable<MyClass> MyMethod()
  {
     using (_unitOfWork = new UnitOfWork())
     {
        var myEntities= _unitOfWork.MyEntityRepository.Get();

        var result = ... some logic to convert myEntities collection to IEnumerable<MyClass> 
        return result;
     }
  }

我的问题是如果有问题using(_unitOfWork = new UnitOfWork),如何为MyMethod编写单元测试?在这种情况下,我如何使用假的UnitOfWork和Fake上下文?谢谢你的任何建议。

2 个答案:

答案 0 :(得分:1)

您必须通过构造函数注入将UnitOfWork工厂注入包含MyMethod方法的类中,如下所示:

public class MyClass
{
    private readonly Func<UnitOfWork> unitOfWorkFactory;

    public MyClass(Func<UnitOfWork> unitOfWorkFactory)
    {
        this.unitOfWorkFactory = unitOfWorkFactory;
    }

    public IEnumerable<MyClass> MyMethod()
    {
        using (unitOfWork = unitOfWorkFactory())
        {
            //..
        }
    }
}

请注意,该课程需要Func<UnitOfWork>而不是UnitOfWork,因为我假设您希望每个MyMethod的来电都有UnitOfWork的新实例。

在测试中,您创建了一个假的UnitOfWork,然后您可以将其传递给MyClass实例,如下所示:

var sut = new MyClass(() => fakeInstance);

您还需要确保UnitOfWork可以伪造。例如,由于它是一个具体的类,您需要确保相关的方法是virtual。另一种方法是使IUnitOfWork实现UnitOfWork实现且MyClass使用的接口stdin

答案 1 :(得分:1)

为了让你的课程更加虚假和可测试我建议尽可能抽象你的UnitOfWorkRepositories,然后使用工厂将它们注入依赖它们的类中。

public interface IUnitOfWork : IDisposable {
    ... repositories 
    IMyEntityRepository MyEntityRepository;
    ...
}

您的UnitOfWork将来自该界面

public class UnitOfWork : IUnitOfWork {...}

<强> IUnitOfWorkFactory

public interface IUnitOfWorkFactory {
    IUnitOfWork Create();
}

这样,依赖类可以看起来像这样

public class MyDependentClass {
    private readonly IUnitOfWorkFactory unitOfWorkFactory;

    public MyDependentClass (IUnitOfWorkFactory unitOfWorkFactory) {
        this.unitOfWorkFactory = unitOfWorkFactory;
    }

    public IEnumerable<MyClass> MyMethod() {
         using (var _unitOfWork = unitOfWorkFactory.Create()) {
             var myEntities= _unitOfWork.MyEntityRepository.Get();

             var result = ... some logic to convert myEntities collection to IEnumerable<MyClass> 
             return result;
         }
    }
}

现在您可以模拟/伪造您的UnitOfWorkRepositories,而无需伪造上下文。

假设你想在调用MyMethod之后测试/验证UOW是否已被处理

(我正在使用MoqFluentAssert进行演示)

您可以按如下方式构建测试:

[TestMethod]
public void UOW_Should_Be_Disposed() {
    //Assert
    var fake_entities = Enumerable.Range(1, 10).Select(i => new MyEntity());
    var mockRepository = new Mock<IMyEntityRepository>();
    mockRepository.Setup(m => m.Get()).Returns(fake_entities);
    var mockUOW = new Mock<IUnitOfWork>();
    mockUOW.Setup(m => m.MyEntityRepository).Returns(mockRepository.Object);
    var mockFactory = new Mock<IUnitOfWorkFactory>();
    mockFactory.Setup(m => m.Create()).Returns(mockUOW.Object);

    //Act
    var sut = new MyDependentClass(mockFactory.Object);
    var output = sut.MyMethod().ToList();

    //Assert
    output.Should().NotBeNull();
    output.Should().HaveCount(10);
    output.Should().ContainItemsAssignableTo<MyClass>();
    mockUOW.Verify(m => m.Dispose());
}

以上显示了如何使用上述框架轻松测试所有内容。

希望这有帮助