android-Androidd单元测试-Espresso


title: android-Androidd单元测试-Espresso
categories: Android
tags: [android, espresso, 单元测试]
date: 2020-02-23 00:36:26
comments: false

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 文件.

单元测试分两种,

  1. [Context 测试](#简单的 Context 测试) : 获取某个 activity 进行简单的测试, 不能测试有线程等待的操作, 不能测试 ui 相关操作.
  2. [Espresso 使用](#Espresso 使用) : 可以测试有线程等待的操作, 可以测试 ui 相关操作.

TODO:

  • 跳转 activity, 不自动退出 app
  • 输入 慢于其他操作

Context 测试

  1. build.gradle 中加入

    dependencies {
        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'
    }
    
  2. 添加测试用例

    @RunWith(AndroidJUnit4ClassRunner.class)
    public class ExampleInstrumentedTest {
          
          
    
        private final String TAG = "--- aut";
        private Context mCtx = null;
    
        @Before
        public void initContext() {
          
          
            mCtx = getInstrumentation().getTargetContext();
        }
    
        @Test
        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()));
        }
    }
    
  3. run 一下这个用例.


Espresso 使用

  1. build.gradle 中加入

    dependencies {
        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'
    }
    
  2. 添加测试用例

    @RunWith(AndroidJUnit4.class)
    @LargeTest
    public class EspressoTest {
          
          
        private static final String TAG = "--- EspressoTest";
    
        @Rule
        public ActivityTestRule<MainActivity> mActivityRule =
                new ActivityTestRule<>(MainActivity.class);
    
        @Test
        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());
        }
    }
    
  3. run 一下这个用例. (输入测试框架自动输入)


获取 Activity 的两种方式

  1. ActivityTestRule

     @Rule
    public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);
    
        @Test
        public void Test_hello() {
          
          
            MainActivity mainActy = mActivityRule.getActivity();
        }
    }
    
  2. ActivityScenario

    private MainActivity mActivity = null;
    
    @Before
    public void launchActivity() {
          
          
        ActivityScenario<MainActivity> actSro = ActivityScenario.launch(MainActivity.class);
        actSro.onActivity((activity) -> {
          
          
            mActivity = activity;
        });
    }
    
    @Test
    public void Test_hello() {
          
          
    	MainActivity mainActy = mActivity;
    }
    

挂起 Activity

单元测试都不是在 ui 线程执行, 所以 Thread.sleep 并不会阻塞 ui 线程, 只是阻塞了测试线程.

每次测试完用例, app 都会退到 后台. 可以使用测试线程睡眠的 骚操作, 阻止单元测试结束 进而防止 app 退到后台, 此时 ui 是可以操作的

@After
public void suspending() {
    
    
    try {
    
    
        Thread.sleep(3000 * 100000);
    } catch (InterruptedException e) {
    
    
        e.printStackTrace();
    }
}

模拟 按键点击

onView(isRoot()).perform(pressKey(KeyEvent.KEYCODE_BACK)); // 模拟 点击 返回键

UI 显示必须在 UI 线程

测试线程不能进行 ui 操作, ui 必须跑在 ui 线程中.

@Test
public void Test_tips() {
    
    
    mActivity.runOnUiThread(() -> {
    
    
        Tools.Tips01(mActivity, "", null);
    });
}

备忘单

  • Espresso 备忘单 (各种模拟操作) - https://developer.android.com/training/testing/espresso/cheat-sheet?hl=zh-cn

踩坑

androidjunit4 deprecated 废弃问题

参考: https://stackoverflow.com/questions/52776716/androidjunit4-class-is-deprecated-how-to-use-androidx-test-ext-junit-runners-an

  1. The gradle file should contain the following line: androidTestImplementation 'androidx.test.ext:junit:1.1.1'
  2. Change test class to AndroidJUnit4ClassRunner from AndroidJUnit4

还有就是 instrumentationregistry.gettargetcontext() deprecated 问题

参考: https://mlog.club/article/3900739


报错: application installation failed

可以尝试一下几种方式

  1. 这有可能是模拟器(手机)上原来安装过同名app但是签名等不一样,在手机上删除该app即可。
  2. 点击Build->Clean Project,然后再次Build->Rebuild Project即可。
  3. 点击File->Setting->Build,Execution,Deployment->Instant Run,将enable instant run... 的勾去掉。
  4. 开启模拟器 调试选项 中的 usb 调试usb 安装

模拟键盘输入不正确

比如 EditText 控件输入 yangx world

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.


Guess you like

Origin blog.csdn.net/yangxuan0261/article/details/104456647