Android测试初体验

    技术2022-07-11  96

    Android测试初体验

    前言介绍编码gradle配置编写普通类编写测试类 注意点Point onePoint twoPoint Three 资料

    前言

    对于任何一个开发人员来说,测试必然是不可缺少的一部分。以前开发都是直接run代码到模拟器或者实体机上面进行实体测试,虽然说这样的测试,可以更加直观的看出问题。但是进行单元测试的话,需要较大的代码量来写测试用例,而且实体测试耗时更长,费时费力。所以想要学习如何更高效的进行代码测试。

    介绍

    稍微了解了一下(看了半天的样子吧,这篇文章只是为了暂时记录一下遇到的坑,而不是个全方位系统的介绍,所以如果有错或者需要补充的地方请在评论区指出),测试大致分为三类:

    小型测试是指单元测试,用于验证应用的行为,一次验证一个类。中型测试是指集成测试,用于验证模块内堆栈级别之间的互动或相关模块之间的互动。大型测试是指端到端测试,用于验证跨越了应用的多个模块的用户操作流程。 本文主要进行了单元测试,使用了Junit4和 Robolectric。主要是跟着资源5的内容进行了代码的编写,但是由于资源5的年代久远,所以有一些内容发生了改变。这里主要是为了记录和资源5所描述的不一样的地方。

    编码

    gradle配置

    向app的build.gradle中加入

    android { testOptions { unitTests { includeAndroidResources = true } } } dependencies { testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:4.2.1' testImplementation 'androidx.test:core:1.2.0' }

    编写普通类

    这里写了两个Activity,在MainActivity里面使用一个TextView,点击TextView跳转到SecondActivity

    1.MainActivity

    package com.example.androidtestlearning import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) tv_turn_new_activity.setOnClickListener { startActivity(Intent(this,SecondActivity::class.java)) } } }

    2.SecondActivity(就是一个空的什么都没写的activity)

    package com.example.androidtestlearning import androidx.appcompat.app.AppCompatActivity import android.os.Bundle class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) } }

    编写测试类

    用来测试是否点击了MainActivity里的tv_turn_new_activity能跳转到SecondActivity

    package com.example.androidtestlearning import android.content.Intent import androidx.test.core.app.ActivityScenario import org.junit.Assert.* import org.junit.Test import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import kotlinx.android.synthetic.main.activity_main.* import org.robolectric.Shadows @RunWith(RobolectricTestRunner::class) class MainActivityTest { @Test @Throws(Exception::class) fun clickText() { val scenario = ActivityScenario.launch( MainActivity::class.java ) scenario.onActivity { activity -> //点击tv activity.tv_turn_new_activity.performClick() //预期的Intent val expectedIntent = Intent(activity, SecondActivity::class.java) //用来获取MainActivity对应的ShadowActivity的instance val shadowActivity = Shadows.shadowOf(activity) //实际获得的Intent val actualIntent = shadowActivity.nextStartedActivity //判断两个Intent是否一样 assertEquals(expectedIntent, actualIntent) } } }

    注意点

    Point one

    旧的资料使用Robolectric.setupActivity(MainActivity.class); 来获取activity,然后发现setupActivity方法已经被弃用了,文档上写的

    Use {@link androidx.test.core.app.ActivityScenario} instead, which works with instrumentation tests too.

    于是就直接跳转到ActivityScenario类里去看,是这样推荐使用的

    * <pre>{@code * Before: * MyActivity activity = Robolectric.setupActivity(MyActivity.class); * assertThat(activity.getSomething()).isEqualTo("something"); * * After: * try(ActivityScenario<MyActivity> scenario = ActivityScenario.launch(MyActivity.class)) { * scenario.onActivity(activity -> { * assertThat(activity.getSomething()).isEqualTo("something"); * }); * }

    那么我就直接把这一段代码ctrl+c ctrl+v了上去,然后发现找不到ActivityScenario。我就google了一下,android developer是这样配置的gradle

    dependencies { // Core library androidTestImplementation 'androidx.test:core:1.0.0' // AndroidJUnitRunner and JUnit Rules androidTestImplementation 'androidx.test:runner:1.1.0' androidTestImplementation 'androidx.test:rules:1.1.0' // Assertions androidTestImplementation 'androidx.test.ext:junit:1.0.0' androidTestImplementation 'androidx.test.ext:truth:1.0.0' androidTestImplementation 'com.google.truth:truth:0.42' // Espresso dependencies androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.1.0' androidTestImplementation 'androidx.test.espresso:espresso-web:3.1.0' androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.1.0' // The following Espresso dependency can be either "implementation" // or "androidTestImplementation", depending on whether you want the // dependency to appear on your APK's compile classpath or the test APK // classpath. androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.1.0' }

    然后发现这样添加之后还是找不到ActivityScenario,我的测试类是写在test文件夹而不是androidtest里面的。而androidTestImplementation是为androidTest里面的文件所依赖的,所以改为testImplementation,即可找到此类。

    Point two

    我之前根据资料没有添加这几行代码

    android { testOptions { unitTests { includeAndroidResources = true } } }

    导致一直报错

    No such manifest file: .\AndroidManifest.xml

    Point Three

    虽然我的程序运行没有错误了,但是它的expectedIntent和actualIntent判断出来不一样emmmm我也不知道为什么(有大佬知道的话,能告诉我是为什么吗)

    java.lang.AssertionError: expected: android.content.Intent<Intent { cmp=com.example.androidtestlearning/.SecondActivity }> but was: android.content.Intent<Intent { cmp=com.example.androidtestlearning/.SecondActivity }> Expected :android.content.Intent<Intent { cmp=com.example.androidtestlearning/.SecondActivity }> Actual :android.content.Intent<Intent { cmp=com.example.androidtestlearning/.SecondActivity }>

    资料

    Android Developer TestAndroidX Test DocumentGithub Android testing-samplesRobolectric用Robolectric来做Android unit testingCodelab
    Processed: 0.014, SQL: 9