1. 程式人生 > >在Android上測試非同步任務——單元測試

在Android上測試非同步任務——單元測試

Android中的測試(寬泛的定義)是一個單元測試集合的擴充套件。涉及初始化、關閉測試,包含setUp()和tearDown()操作,使用反射 的方式推斷出不同的測試方式(從JUnit4開始我們就可以使用註釋來指定的優先順序和執行所有測試)。一個典型的測試結構如下:

public class MyManagerTest extends ActivityTestCase { 

    public MyManagerTest(String name) { 
        super(name); 
    } 

    protected void setUp() throws Exception { 
        super
.setUp(); } protected void tearDown() throws Exception { super.tearDown(); } public void testDummyTest() { fail("Failing test"); } }

這是一個非常明顯的示例:實際開發中,我們想要測試例如HTTP響應、SQL儲存等等。在Sixt我們遵從一種Manager/Model方法:每 個Model包含一個實體(車、顧客等)的表現。每個Manager用不同的模型(例如,我們的LoginManager可能需要使用者與之互動的模型)聚 合成一套功能。

大多數的Manager集中執行HTTP請求是要從後臺獲取資料。例如,我們用下面的程式碼來執行使用者的登入:

mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() { 
    @Override 
    public void onFailure(Throwable throwable) { 
        fail(); 
    } 

    Override 
    public void onSuccess(User customer) { 
    //.. 
} });

應用到我們自己的測試集合後,當得到預期之外的結果時,只是讓這一結果失敗。我們可以看到為什麼在onFailure()函式中我們呼叫了 fail()。接下來,即使我用一個錯誤的使用者名稱也能通過這個測試。思前想後,測試似乎是按照程式碼順序執行的,但並沒有等到回撥函式的結果返回再向下執 行。

這顯然不是一個好方法。因為現在的程式經常通過非同步任務和回撥方法從後臺獲取資料。嘗試UIThread測試仍然不行。

最後,我發現下面這種方法可以行得通。只是用簡單的CountDownLatch訊號物件來實現wait-notify機制(你也可以用syncronized(lock){… lock.notify();},只是這樣程式碼並不美觀而已)

那麼之前的程式碼就變成了下面的模樣:

final CountDownLatch signal = new CountDownLatch(1); 
mLoginManager.performLoginWithUsername("username", "password", new OnLoginListener() { 
    @Override 
    public void onFailure(Throwable throwable) { 
        fail(); 
        signal.countDown(); 
    } 

    Override 
    public void onSuccess(User customer) { 
        signal.countDown(); 
    } 
}); 
signal.await();