2011-02-18 64 views
1

我有一段代碼大致等同於以下內容。重構測試

 

public class ConcreteThread extends OtherThread { 
    private DAOfirst firstDAO; 
    private DAOsecond secondDAO; 
    private TransformService transformService; 
    private NetworkService networkService; 

    public ConcreteThread(DAOfirst first, DAOsecond second, TransformService service1, 
     NetworkService service2) { 
    firstDAO = first; 
    secondDAO = second; 
    transformService = service1; 
    networkService = service2; 
    } 

    public Future go() { 
    Results r1 = firstDAO.getResults(); 
    MyCallable c1 = new MyCallable(r1); 
    return super.getThreadPool().submit(c1); 
    } 

    private class MyCallable implements Callable { 
    private Results result; 
    private Long count; 
    private MyCallable(Results r) { 
     this.result = r; 
     this.count = new Long(0); 
    } 

    public Long call() { 
     Singleton transactions = Singleton.getInstance(); 
     try { 
     transactions.begin(); 
     while(result != null) { 
      Transformed t = transformService.transform(r1); 
      networkService.sendSomewhere(t); 
      count = count += result.size(); 
      secondDao.persist(result); 
      result = firstDao.getNext(result); 
     } 
     } 
     catch (Exception e) { 
     e.printStackTrace(); 
     } 
     finally { 
     transactions.end(); 
     } 
    } 
    } 
 

無論這些類(內或外)的有單元測試,並將其結果是內部類,MyCallable,在它的一個錯誤。在上面給出的代碼的簡化版本中,該錯誤不存在。

因此,讓我們假設您決定修復這個bug,併爲MyCallable執行一些單元測試。我的問題是這個;你將如何去編寫MyCallable內部類的單元測試?

我自己的解決方案是首先重構MyCallableConcreteThreadMyCallable在其自己的文件中被創建爲公共類,並且ConcreteThread現在將DAO,Services和Singleton作爲構造函數參數傳遞給MyCallable,而不是依賴內部類訪問它的私有變量。

然後,我在單元測試中大量使用EasyMock來模擬這些依賴關係,並驗證它們是否以我期望的方式被調用。

所有這一切的結果是MyCallable的代碼比它更大一些。因爲它不再有權訪問ConcreteThread中的私有變量,所以ConcreteThread必須在構造函數中將它們作爲參數傳入,並且MyCallable將它們設置爲私有變量。

你認爲這是錯誤的做法嗎?也許通過執行這種重構,我已經破解了封裝並向代碼庫添加了不必要的樣板文件?你會在測試中使用反射嗎?

回答

3

所有這些的結果是,MyCallable的代碼比它更大一些。由於它不再可以訪問ConcreteThread中的私有變量,因此ConcreteThread必須在構造函數中將它們作爲參數傳遞,並且MyCallable將它們設置爲私有變量。

這是一個很好的結果,MyCallable不再依賴於ConcreteThread的變化。

我認爲問題和答案是相當主觀的,但我認爲你在重構中遵循SOLID原則(這是一件好事)。

如果你能,使MyCallable包的保護,而不是公衆:)

+0

+1完全同意。關於封裝,只要你保持你的MyCallable包是本地的(就像Augusto所說的那樣),你並沒有打破封裝,只是放鬆它來幫助測試,這是很常見的做法。你可能希望在某處發表評論。至於樣板,它不會真的增加代碼的複雜性,所以不要太擔心。稍微多一些的代碼比沒有測試的代碼更好。 – rodion 2011-02-18 12:01:32

1

對我來說,它看起來像,內部類是外部類的實現細節。

所以我提出這個問題,你可以通過爲ConcreteThread.Go()寫一個失敗的單元測試來證明這個錯誤?一旦你改變了內部階層,應該有什麼不同 - 外部可見的變化是什麼?一旦你弄清楚了 - 你就會在路上。