本文主要內容
- 1、單元測試介紹
- 2、java單元測試
- 3、android單元測試
- 4、常用方法介紹
1、單元測試介紹
單元測試,是指對軟件中的最小可測試單元進行檢查和驗證。
在Java中,最小單元可以是類也可以是方法,比如剛剛開發(fā)完成一個下載的方法,此時可以用單元測試其是否ok。如果不用單元測試,用手寫代碼調用的方式,則工作量會較大。
使用Android studio進行單元測試,一共有兩種類型,一種就是普通的java單元測試,另一種就是android單元測試,android單元測試包括對ui測試,activity的相關方法進行測試等等,需要context參數

進行單元測試需要引入對應的依賴。
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
前面3個依賴包,在創(chuàng)建工程的時候會默認加進來,最后一個貌似不會默認添加,需要手動添加。最后一個依賴包與activity相關的單元測試有關。
2、java單元測試
以一個最簡單的例子,計算器為例:
public class Util {
public static int add(int a, int b){
return a + b;
}
public int addInt(int a, int b){
return a + b;
}
}
Util類中有一個靜態(tài)方法,一個非靜態(tài)方法,都是簡單的相加邏輯。接下來,可以右鍵選中方法,然后點擊goto選項,生成對應的單元測試文件。



最后一步中可以選擇為當前類中的哪些方法添加單元測試,也可以勾選before和after兩個選項,顧名思義,before和after方法分別在單元測試前后調用,我們可以在這兩個方法中做一些事情,例如初始化、回收等等。
public class UtilTest {
Util util;
@Before
public void setUp() throws Exception {
util = new Util();
System.out.println("sutup");
}
@After
public void tearDown() throws Exception {
System.out.println("tearDown");
}
@Test
public void add() {
assertEquals(2,Util.add(1, 1));
}
@Test
public void addInt() {
assertEquals(2, util.addInt(1,1));
}
}
Util類中,寫了一個靜態(tài)方法和非靜態(tài)方法,其實就是為了演示 setUp 方法的作用,如果在單元測試中需要初始化一些類,則可以在 setUp 中初始化,在測試方法中使用已經初始化過的實例即可。
Java單元測試運行依賴于 JVM,執(zhí)行單元測試方法非常簡單,右鍵單元測試文件執(zhí)行即可,也可以選擇某個方法,只執(zhí)行這一個方法。
3、android單元測試
Android單元測試,它依賴于Android的執(zhí)行環(huán)境,也就是需要在android機器上運行。與java單元測試相比,它有一點點的不同。
前一章中講過java單元測試,提到了 before 和 after 這兩個選項,有點類似于切面編程,可以在其中做一些初始化的動作。但android中最常用的是activity,如何在activity中也添加一些周期回調函數呢?
@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(MainActivity.class){
@Override
protected Intent getActivityIntent() {
Intent intent = new Intent();
intent.putExtra("data","world");
return intent;
}
@Override
protected void beforeActivityLaunched() {
super.beforeActivityLaunched();
Log.i("okunu","before");
}
};
通過如上方式添加activity相關的單元測試周期回調函數。
getActivityIntent ,顧名思義,對啟動activity的intent進行測試封裝,上例中就添加了相關的參數。值得注意的是,為何 intent 中沒有添加 action 呢?我猜想就是 ActivityTestRule 對象已經與MainActivity相關聯了,它就是要去啟動MainActivity的,加不加action都無所謂了。這里也隱含了另一層意思,要對某個activity相關的任何方法進行單元測試,都要添加與之相關聯的ActivityTestRule 對象。
beforeActivityLaunched ,就是在activity啟動之前執(zhí)行的函數
本例中,有一個EditText,TextView和一個Button,點擊Button,將EditText中的文字顯示到TextView,同時也會接收Intent中的相關參數,顯示在TextView中
public class MainActivity extends AppCompatActivity {
String mData;
TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mData = getIntent().getStringExtra("data");
text = (TextView)findViewById(R.id.text);
text.setText(mData != null ? mData : "");
}
public void sayHello(View view){
EditText edit = (EditText)findViewById(R.id.edit);
String str = "hello " + mData + " " + edit.getText().toString() + " !";
text.setText(str);
}
}
它的單元測試類依然可以和第2節(jié)一樣生成,我們看看詳細代碼:
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<MainActivity>(MainActivity.class){
@Override
protected Intent getActivityIntent() {
Intent intent = new Intent();
intent.putExtra("data","world");
return intent;
}
@Override
protected void beforeActivityLaunched() {
super.beforeActivityLaunched();
Log.i("okunu","before");
}
};
Context appContext;
@Before
public void setUp() throws Exception {
Log.i("okunu","setUp");
appContext = InstrumentationRegistry.getTargetContext();
}
@After
public void tearDown() throws Exception {
Log.i("okunu","tearDown");
}
@Test
public void sayHello() {
onView(withId(R.id.edit)).perform(typeText("jim"), closeSoftKeyboard()); //line 1
onView(withText("hello")).perform(click()); //line 2
String expectedText = "hello " + "world " + "jim" + " !";
onView(withId(R.id.text)).check(matches(withText(expectedText))); //line 3
}
}
注意,context是可以獲取的。另外最重要的就是理解這幾個生命周期回調函數的作用。可以在setUp函數中獲取context,如果與activity啟動相關的要改動,則在ActivityTestRule類中修改即可。
4、常用方法介紹
在android單元測試中需要獲取到某個view,如何獲取呢?
- withText:通過文本來獲取對象,如:ViewInteraction save = onView(withText(“保存”)) ;
- withId:通過id來獲取對象,如:ViewInteraction save = onView(withId(R.id.save)) ;
通過文本獲取,如上例,如果某個view上的文本是“保存”,則返回此view。通過id獲取就比較容易理解了,建議使用id方式。
那么對view操作的接口又有哪些呢?
使用方式是onView(…).perform() 。也可以執(zhí)行多個操作在一個perform中如:perform(click(),clearText()) 。所有的操作都有一個前提 ———— 就是要執(zhí)行的view必須在當前界面上顯示出來(有且可見)。
| 方法名 | 含義 |
|---|---|
| click() | 點擊view |
| clearText() | 清除文本內容 |
| swipeLeft() | 從右往左滑 |
| swipeRight() | 從左往右滑 |
| swipeDown() | 從上往下滑 |
| swipeUp() | 從下往上滑 |
| click() | 點擊view |
| closeSoftKeyboard() | 關閉軟鍵盤 |
| pressBack() | 按下物理返回鍵 |
| doubleClick() | 雙擊 |
| longClick() | 長按 |
| scrollTo() | 滾動 |
| replaceText() | 替換文本 |
| openLinkWithText() | 打開指定超鏈 |