# Unit Test - 測試Android Components --- * 延續上一篇的筆記專案架構 [Unit Test - 基本的單元測試寫法](https://hackmd.io/awJiLPm1Q-KO7D63AC1VAg) ## 這篇會用到Android test,也就是整合測試 * 整合測試會使用到Android Studio的模擬器 * 會使用到@Bdfore 、 @After ..等聲明 ## 開始吧 ### 情境 * 輸入一個字串,比對context的resource ID是否相同 * 接續上一篇的架構,新增一個類別ResourceComparer ![](https://i.imgur.com/Do5CT4p.png) ### 試想TDD步驟一: *選定一個功能,新增測試案例* * 定義函數參數,它需要context, resource ID, 比對的字串 ```kotlin= class ResourceComparer { //判斷參數的recource ID跟輸入的字串是否相同 fun isEqual(context: Context, resId: Int, string:String): Boolean{ return true } } ``` * 新增測試案例 * 這次因為我們要測試的內容是包含Android Compenents,這邊例子是context,所以要把測試程式寫在\app\src\androidTest這個路徑 ![](https://i.imgur.com/fWGu6Hv.png) ### 試想TDD步驟二: *執行測試,得到 Failed(紅燈)* * 這裡我們使用app name來當我們的recource id ```kotlin= class ResourceComparerTest{ private val resourceComparer = ResourceComparer() @Test fun stringResourceNotSameAsGivenString_returnsFalse(){ val context = ApplicationProvider.getApplicationContext<Context>() val result = resourceComparer.isEqual(context, R.string.app_name,"hello" ) assertThat(result).isFalse() } } ``` ![](https://i.imgur.com/3dN8x2C.png) ### 試想TDD步驟三: *實作「夠用」的產品程式* * 這邊把情境中的條件寫出來 ```kotlin= class ResourceComparer { fun isEqual(context: Context, resId: Int, string:String): Boolean{ return context.getString(resId) == string } } ``` ### 試想TDD步驟四: *再次執行測試,得到 Passed(綠燈)* ![](https://i.imgur.com/8cEIc9r.png) ### 試想TDD步驟五: *重構程式* * 把測試程式的條件寫完- 當resource ID 跟輸入字串相同 ```kotlin= @Test fun stringResourceSameAsGivenString_returnsTrue(){ val context = ApplicationProvider.getApplicationContext<Context>() val result = resourceComparer.isEqual(context, R.string.app_name,"unittesting" ) assertThat(result).isTrue() } @Test fun stringResourceNotSameAsGivenString_returnsFalse(){ val context = ApplicationProvider.getApplicationContext<Context>() val result = resourceComparer.isEqual(context, R.string.app_name,"hello" ) assertThat(result).isFalse() } ``` ![](https://i.imgur.com/K9KwcY6.png) ## 優化 * 這個測試程式需要ResourceComparer類別的實例 * 直接宣告一個全域變數來賦予實例是不好的寫法 * 較好的做法是,當個別的測試程式要執行的時候再去產生實例,避免測試程式之間產生干擾,造成測試結果可能不穩定 * 所以Junit提供了@Before 跟 @After聲明可以使用 * @Before就是在@Test的程式要執行之前都會先執行@Before定義的函數 * @After就是在@Test的函數執行完畢之後才執行@After定義的函數,在這邊的例子還用不到。 ```kotlin= private lateinit var resourceComparer :ResourceComparer // ↓ 這樣寫不好 // private val resourceComparer = ResourceComparer() @Before fun setUp(){ //每次執行@Test底下的函數之前都會先產生實例 resourceComparer = ResourceComparer() } @After fun tearDown(){ } @Test fun stringResourceSameAsGivenString_returnsTrue() { val context = ApplicationProvider.getApplicationContext<Context>() val result = resourceComparer.isEqual(context, R.string.app_name, "unittesting") assertThat(result).isTrue() } @Test fun stringResourceNotSameAsGivenString_returnsFalse() { val context = ApplicationProvider.getApplicationContext<Context>() val result = resourceComparer.isEqual(context, R.string.app_name, "hello") assertThat(result).isFalse() } ``` ## 補充說明 * 在AndroidTest(整合測試)中,它沒辦法像unitTest可以使用反引號命名函數,例如: `if something returns false`,可能是系統上有什麼考量吧.也許以後可以? * 整合測試的函數命名,盡量描述清楚 ###### tags: `test` `Unit Test` `TDD` `kotlin` `Android`