Android测试初体验

前言

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

介绍

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

  1. 小型测试是指单元测试,用于验证应用的行为,一次验证一个类。
  2. 中型测试是指集成测试,用于验证模块内堆栈级别之间的互动或相关模块之间的互动。
  3. 大型测试是指端到端测试,用于验证跨越了应用的多个模块的用户操作流程。
    本文主要进行了单元测试,使用了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 }>

资料

  1. Android Developer Test
  2. AndroidX Test Document
  3. Github Android testing-samples
  4. Robolectric
  5. 用Robolectric来做Android unit testing
  6. Codelab
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值