在Android Studio中進行單元測試和UI測試,androidui
本篇教程翻譯自Google I/O 2015中關於測試的codelab,掌握科學上網的同學請點擊這裡閱讀:Unit and UI Testing in Android Studio。能力有限,如有翻譯錯誤,請批評指正。如需轉載,請註明出處。
Github下載測試源碼
目錄
- 在Android Studio中進行單元測試和UI測試 - 1.概述
- 在Android Studio中進行單元測試和UI測試 - 2.建立新的Android Studio工程
- 在Android Studio中進行單元測試和UI測試 - 3.配置支援單元測試的工程
- 在Android Studio中進行單元測試和UI測試 - 4.建立第一個單元測試
- 在Android Studio中進行單元測試和UI測試 - 5.運行單元測試
- 在Android Studio中進行單元測試和UI測試 - 6.配置支援Instrumentation測試的工程
- 在Android Studio中進行單元測試和UI測試 - 7.為app添加簡單的互動
- 在Android Studio中進行單元測試和UI測試 - 8.建立並運行Espresso測試
- 在Android Studio中進行單元測試和UI測試 - 9.祝賀!
1.概述
在這個codelab中,你將學習如何在Android Studio中配置工程用於測試,在開發機器上編寫並運行單元測試,以及如何在手機上做功能UI測試。
你會學到什麼
- 更新包含JUnit和Android Testing Support Library的Gradle構建檔案
- 編寫運行在本機Java虛擬機器上的單元測試
- 編寫運行在手機或者虛擬機器上的Espresso測試
你需要什麼
- Android Studio v1.2+
- Android 4.0+的測試裝置
2.建立新的Android Studio工程
如果是第一次啟動Android Studio,從歡迎頁面選擇“Start a new Android Studio project”。如果已經開啟了一個工程,選擇File>New>New Project...
“Create new project”嚮導會指導整個過程,在第一頁輸入如下內容:
| Setting |
Value |
| Application Name |
TestingExample |
| Company demain |
testing.example.com |
這樣會保證你的代碼同codelab講解的內容具有一致的命名。其他的選項都設定為預設,一路點擊Next直到工程建立完畢。
點擊Run按鈕檢查app是否運行正常,要麼從模擬器列表中選擇一個啟動,要麼確認開啟了debug模式的裝置通過USB同電腦正確串連。
app目前沒有做任何事情,但是螢幕上應該顯示“Hello world!”和app的名字。
經常被問及的問題
- 如何安裝Android Studio?
- 如何開啟USB調試?
- 為什麼Android Studio找不到我的裝置?
- Android錯誤:無法將*.apk安裝到裝置上:逾時?
3.配置支援單元測試的工程
在寫測試之前,讓我們做下簡單的檢查,確保工程配置正確。
首先,確認在Build Variants視窗內的Test Artifact中選擇了"Unit Tests"。
然後,在工程的src檔案夾內建立test和test/java檔案夾。需要注意的是,你不能在Android視圖下進行這些操作,要麼在系統的檔案管理工具內建立,要麼在工程視窗左上方點擊下拉式功能表選擇Project視圖。最終的工程結構應該是這樣的:
(在codelab的剩餘部分,你可以返回繼續使用Android工程視圖)
最後,開啟工程的build.gradle(Module:app)檔案,添加JUnit4依賴,點擊Gradle sync按鈕。
build.gradle
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.1.1' testCompile 'junit:junit:4.12'}
當你同步Gradle配置時,可能需要連網下載JUnit依賴。
4.建立第一個單元測試
現在,萬事俱備,讓我們開始寫第一個測試吧。首先,建立一個非常簡單的被測類:Calculator類。
然後,向類中添加一些基本的算術運算方法,比如加法和減法。將下列代碼複製到編輯器中。不用擔心實際的實現,暫時讓所有的方法返回0。
Calculator.java
package com.example.testing.testingexample;public class Calculator { public double sum(double a, double b){ return 0; } public double substract(double a, double b){ return 0; } public double divide(double a, double b){ return 0; } public double multiply(double a, double b){ return 0; }}
Android Studio提供了一個快速建立測試類別的方法。只需在編輯器內右鍵點擊Calculator類的聲明,選擇Go to > Test,然後"Create a new test…"
在開啟的交談視窗中,選擇JUnit4和"setUp/@Before",同時為所有的計算機運算產生測試方法。
這樣,就會在正確的檔案夾內(app/src/test/java/com/example/testing/testingexample)產生測試類別架構,在架構內填入測試方法即可。下面是一個樣本:
Calculator.java
package com.example.testing.testingexample;import org.junit.Before;import org.junit.Test;import static org.junit.Assert.*;public class CalculatorTest { private Calculator mCalculator; @Before public void setUp() throws Exception { mCalculator = new Calculator(); } @Test public void testSum() throws Exception { //expected: 6, sum of 1 and 5 assertEquals(6d, mCalculator.sum(1d, 5d), 0); } @Test public void testSubstract() throws Exception { assertEquals(1d, mCalculator.substract(5d, 4d), 0); } @Test public void testDivide() throws Exception { assertEquals(4d, mCalculator.divide(20d, 5d), 0); } @Test public void testMultiply() throws Exception { assertEquals(10d, mCalculator.multiply(2d, 5d), 0); }}
請將代碼複製到編輯器或者使用JUnit架構提供的斷言來編寫自己的測試。
5.運行單元測試
終於到運行測試的時候了!右鍵點擊CalculatorTest類,選擇Run > CalculatorTest。也可以通過命令列運行測試,在工程目錄內輸入:
./gradlew test
無論如何運行測試,都應該看到輸出顯示4個測試都失敗了。這是預期的結果,因為我們還沒有實現運算操作。
讓我們修改Calculator類中的sum(double a, double b)方法返回一個正確的結果,重新運行測試。你應該看到4個測試中的3個失敗了。
Calculator.java
public double sum(double a, double b){ return a + b;}
作為練習,你可以實現剩餘的方法使所有的測試通過。
可能你已經注意到了Android Studio從來沒有讓你串連裝置或者啟動模擬器來運行測試。那是因為,位於src/tests目錄下的測試是運行在本地電腦Java虛擬機器上的單元測試。編寫測試,實現功能使測試通過,然後再添加更多的測試...這種工作方式使快速迭代成為可能,我們稱之為測試驅動開發。
值得注意的是,當在本地運行測試時,Gradle為你在環境變數中提供了包含Android架構的android.jar包。但是它們功能不完整(所以,打個比方,你不能單純調用Activity的方法並指望它們生效)。推薦使用Mockito等mocking架構來mock你需要使用的任何Android方法。對於運行在裝置上,並充分利用Android架構的測試,請繼續閱讀本篇教程的下個部分。
6.配置支援Instrumentation測試的工程
雖然在Android架構內支援運行instrumentation測試,但是目前開發重心主要集中在剛剛發布的作為Android Testing Support Library一部分的新的AndroidJUnitRunner。測試庫包含Espresso,用於運行功能UI測試的架構。讓我們通過編輯build.gradle的相關部分來把它們添加進我們的工程。
build.gradle
apply plugin: 'com.android.application'android { compileSdkVersion 22 buildToolsVersion "22.0.1" defaultConfig { applicationId "com.example.testing.testingexample" minSdkVersion 15 targetSdkVersion 22 versionCode 1 versionName "1.0" //ADD THIS LINE: testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } //ADD THESE LINES: packagingOptions { exclude 'LICENSE.txt' }}dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:22.0.0' //← MAKE SURE IT’S 22.0.0 testCompile 'junit:junit:4.12' //ADD THESE LINES: androidTestCompile 'com.android.support.test:runner:0.2' androidTestCompile 'com.android.support.test:rules:0.2' androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'}
重要:由於一些依賴版本衝突,你需要確認com.android.support:appcompat-v7庫的版本號碼是22.0.0,像上面的程式碼片段一樣。
另外,Android Studio可能會提醒你Build Tools 22.0.1沒有安裝。你應該接受修複建議,Studio會為你安裝Build Tools或者在build.gradle中把這行修改成已經安裝在你電腦的版本。
上面的工作完成後,在Build Variants視窗內切換成Android Instrumentation Tests,你的工程應該自動同步。如果沒有,點擊Gradle sync按鈕。
7.為app添加簡單的互動
在使用Espresso進行UI測試前,讓我們為app添加一些Views和簡單的互動。我們使用一個使用者可以輸入名字的EditText,歡迎使用者的Button和用於輸出的TextView。開啟res/layout/activity_main.xml,粘貼如下代碼:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:text="@string/hello_world" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <EditText android:hint="Enter your name here" android:id="@+id/editText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/textView"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Say hello!" android:layout_below="@+id/editText" android:onClick="sayHello"/></RelativeLayout>
還需要在MainActivity.java中添加onClick handler:
MainActivity.java
public void sayHello(View v){ TextView textView = (TextView) findViewById(R.id.textView); EditText editText = (EditText) findViewById(R.id.editText); textView.setText("Hello, " + editText.getText().toString() + "!");}
現在可以運行app並確認一切工作正常。在點擊Run按鈕之前,確認你的Run Configuration沒有設定為運行測試。如需更改,點擊下拉選項,選擇app。
8.建立並運行Espresso測試
在工程的整體視圖上,找到以(androidTest)尾碼結尾的包名並建立一個新的Java類。可以將它命名為MainActivityInstrumentationTest,將如下代碼粘貼過去。
** MainActivityInstrumentationTest.java
package com.example.testing.testingexample;import android.support.test.InstrumentationRegistry;import android.support.test.espresso.action.ViewActions;import android.support.test.rule.ActivityTestRule;import android.support.test.runner.AndroidJUnit4;import android.test.ActivityInstrumentationTestCase2;import android.test.suitebuilder.annotation.LargeTest;import org.junit.After;import org.junit.Before;import org.junit.Rule;import org.junit.Test;import org.junit.runner.RunWith;import static android.support.test.espresso.Espresso.onView;import static android.support.test.espresso.action.ViewActions.click;import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;import static android.support.test.espresso.action.ViewActions.typeText;import static android.support.test.espresso.assertion.ViewAssertions.matches;import static android.support.test.espresso.matcher.ViewMatchers.withId;import static android.support.test.espresso.matcher.ViewMatchers.withText;@RunWith(AndroidJUnit4.class)@LargeTestpublic class MainActivityInstrumentationTest { private static final String STRING_TO_BE_TYPED = "Peter"; @Rule public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>( MainActivity.class); @Test public void sayHello(){ onView(withId(R.id.editText)).perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard()); //line 1 onView(withText("Say hello!")).perform(click()); //line 2 String expectedText = "Hello, " + STRING_TO_BE_TYPED + "!"; onView(withId(R.id.textView)).check(matches(withText(expectedText))); //line 3 }}
測試類別通過AndroidJUnitRunner運行,並執行sayHello()方法。下面將逐行解釋都做了什麼:
- 1.首先,找到ID為
editText的view,輸入Peter,然後關閉鍵盤;
- 2.接下來,點擊
Say hello!的View,我們沒有在布局的XML中為這個Button設定id,因此,通過搜尋它上面的文字來找到它;
- 3.最後,將
TextView上的文本同預期結果對比,如果一致則測試通過;
你也可以右鍵點擊網域名稱運行測試,選擇Run>MainActivityInstrume...(第二個帶Android表徵圖的)
這樣就會在模擬器或者串連的裝置上運行測試,你可以在手機螢幕上看到被執行的動作(比如在EditText上打字)。最後會在Android Studio輸出通過和失敗的測試結果。
Github下載測試源碼
9.祝賀
我們希望你能喜歡本篇教程,並且開始著手測試你的應用程式。接著你可以學習如下內容: