2016-04-14 122 views
2

单元测试有问题。 我有一个standart Reprository和UnitOfWork模式。 例如,我有一个的UnitOfWork类:程序女巫的另一部分用于一次性方法的单元测试

public class UnitOfWork : IDisposable 
{ 
    private readonly MyDbContext _context; 

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

UnitOfWok作出一些特殊的操作与实体。例如,有一种方法,使用whitch的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; 
    } 
    } 

我的问题是如何编写单元测试的MyMethod如果有农业综合整治开发using(_unitOfWork = new UnitOfWork)?在这种情况下,我怎样才能使用伪造的UnitOfWork和Fake上下文?感谢您的任何建议。

+1

通过没有在UoW类中实例化上下文,而是提供它作为(构造函数)依赖项。 – spender

回答

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,而无需伪造上下文。

比方说,你要测试/验证UOW呼吁MyMethod

后实际配置的(我使用论证的目的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()); 
} 

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

希望这可以帮助

+0

非常感谢你的详细解答。 – user3609841

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是fakeable。例如,因为它是一个具体的类,所以你需要确保相关的方法是virtual。另一种方法是有一个接口IUnitOfWorkUnitOfWork工具和MyClass用途。