2016-04-14 61 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用途。