2017-09-26 74 views
2

有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類並讓它完成剩下的工作。有任何想法嗎?

+1

使用靜態工廠往往會使他們的依賴項孤立測試比他們需要更困難。你是正確的,因爲UI不應該關注UOW。但它與數據服務有關。 – Nkosi

+0

你可以在'UnitOfWorkFactory'中注入一些依賴嗎? – doctorlove

回答

0

使用Mocking框架。單元測試是爲了測試這段代碼而不是分支或連接類。使用Mockito或easymock等模擬框架,模擬UnitOfWorkFactory併爲unitOfWork.Lessons.FindById(id)創建自己的輸出。記住要測試所有的可能性。使用此link瞭解更多關於Mockito。

+0

我已經使用了Moq,但如果我嘲笑UnitOfWorkFactory,我如何將它注入到DataService類中,以便我使用它而不是使用真正的Factory。 – Sisyphus

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核心)

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

不幸的是我出於政治原因不能改變Factory類和導出UnitOfWork,但是非常感謝你的努力。 – Sisyphus

+0

@Sisyphus,我根本沒有改變工廠類。我重構了依賴於工廠類的代碼。這就是你無法更改代碼的意思嗎? – Nkosi

+0

對不起,我不是故意改變工廠,我的意思是將UnitOfWork暴露給外觀。我們需要將它完全封裝在DataService類中,並且即使抽象概念也完全無知。 – Sisyphus

0

我落戶的是,我做的內部構造函數DataService和使用InternalsVisibleToAttribute,這樣我可以覆蓋使其單元測試項目可見工廠和注射和模擬UnitOfWork。

相關問題