android-Androidd单元测试-Espresso
android-Androidd单元测试-Espresso
前篇
- 官方
- Espresso 设置说明 - https://developer.android.com/training/testing/espresso/setup?hl=zh-cn
- 将用户转到其他应用 (有发邮件示例) - https://developer.android.com/training/basics/intents/sending
- Espresso 备忘单 (各种模拟操作) - https://developer.android.com/training/testing/espresso/cheat-sheet?hl=zh-cn
- AndroidX Test 的 JUnit4 规则 - https://developer.android.com/training/testing/junit-rules?hl=zh-cn
- 示例 - https://github.com/android/testing-samples
测试时间稍长, 只要是需要 build gradle 文件.
单元测试分两种,
- [Context 测试](#简单的 Context 测试) : 获取某个 activity 进行简单的测试, 不能测试有线程等待的操作, 不能测试 ui 相关操作.
- [Espresso 使用](#Espresso 使用) : 可以测试有线程等待的操作, 可以测试 ui 相关操作.
单元测试默认使用的是 debug 签名文件打包
C:\Users\%USER_NAME%\.android\debug.keystore
Context 测试
在 build.gradle 中加入
1
2
3
4
5
6
7dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:core:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}添加测试用例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ExampleInstrumentedTest {
private final String TAG = "--- aut";
private Context mCtx = null;
public void initContext() {
mCtx = getInstrumentation().getTargetContext();
}
public void test_getFile() {
final String tempFile = "hello.txt";
try {
Tools.writeFile(mCtx, tempFile, "wolegequ");
} catch (IOException e) {
e.printStackTrace();
}
File fa = Tools.getFile(mCtx, tempFile);
Log.d(TAG, String.format("test_getFile: " + fa.exists()));
}
}run 一下这个用例.
Espresso 使用
在 build.gradle 中加入
1
2
3
4
5
6
7dependencies {
androidTestImplementation 'androidx.test:core:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
}添加测试用例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class EspressoTest {
private static final String TAG = "--- EspressoTest";
public ActivityTestRule<MainActivity> mActivityRule =
new ActivityTestRule<>(MainActivity.class);
public void Test_hello() {
MainActivity mainActy = mActivityRule.getActivity();
EditText etName = mainActy.findViewById(R.id.editText);
// 模拟 输入
onView(withId(R.id.editText)).perform(typeText("yangx world"), ViewActions.closeSoftKeyboard());
Log.d(TAG, "etName:" + etName.getText());
}
}run 一下这个用例. (输入测试框架自动输入)
获取 Activity 的两种方式
ActivityTestRule
1
2
3
4
5
6
7
8
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
public void Test_hello() {
MainActivity mainActy = mActivityRule.getActivity();
}
}ActivityScenario
1
2
3
4
5
6
7
8
9
10
11
12
13
14private MainActivity mActivity = null;
public void launchActivity() {
ActivityScenario<MainActivity> actSro = ActivityScenario.launch(MainActivity.class);
actSro.onActivity((activity) -> {
mActivity = activity;
});
}
public void Test_hello() {
MainActivity mainActy = mActivity;
}
挂起 Activity
单元测试都不是在 ui 线程执行, 所以 Thread.sleep 并不会阻塞 ui 线程, 只是阻塞了测试线程.
每次测试完用例, app 都会退到 后台. 可以使用测试线程睡眠的 骚操作, 阻止单元测试结束 进而防止 app 退到后台, 此时 ui 是可以操作的
1 |
|
模拟 按键点击
1 | onView(isRoot()).perform(pressKey(KeyEvent.KEYCODE_BACK)); // 模拟 点击 返回键 |
UI 显示必须在 UI 线程
测试线程不能进行 ui 操作, ui 必须跑在 ui 线程中.
1 |
|
指定 测试顺序
测试顺序 按 方法名 升序
1 | @FixMethodOrder(MethodSorters.NAME_ASCENDING) // 测试顺序 按 方法名 升序 |
备忘单
- Espresso 备忘单 (各种模拟操作) - https://developer.android.com/training/testing/espresso/cheat-sheet?hl=zh-cn
踩坑
androidjunit4 deprecated 废弃问题
- The gradle file should contain the following line:
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- Change test class to
AndroidJUnit4ClassRunner
fromAndroidJUnit4
还有就是 instrumentationregistry.gettargetcontext() deprecated
问题
参考: https://mlog.club/article/3900739
报错: application installation failed
可以尝试一下几种方式
- 这有可能是模拟器(手机)上原来安装过同名app但是签名等不一样,在手机上删除该app即可。
- 点击Build->Clean Project,然后再次Build->Rebuild Project即可。
- 点击File->Setting->Build,Execution,Deployment->Instant Run,将
enable instant run...
的勾去掉。 - 开启模拟器 调试选项 中的 usb 调试 和 usb 安装
模拟键盘输入不正确
比如 EditText 控件输入 yangx world
1 | onView(withId(R.id.editText)).perform(typeText("yangx world"), ViewActions.closeSoftKeyboard()); |
etName.getText());
获取到的值不对, 且显示上看到也错的.
解决办法: 参考: https://stackoverflow.com/questions/20436968/espresso-typetext-not-working
Looks like I figured out the issue. It had to do with hardware vs software keyboard.
For Emulators:
Go to Settings -> Language & Input -> switch the Default Input to Sample Soft Keyboard.
逍遥模拟器改成
For Phones:
Install a software keyboard from the Play store and switch to it. It appears that the native keyboards of some phones do not work.