代码参考:https://github.com/googlesamples/android-testing

解释参考:

https://www.jianshu.com/p/5732b4afd12f

官网教程:

https://developer.android.google.cn/training/testing/unit-testing/local-unit-tests#setup

一、Android项目的测试基础

1.根据执行环境组织测试目录

Android Studio中的典型项目包含两个放置测试的目录。按如下方式组织测试:

  • androidTest目录应包含在实际或虚拟设备上运行的测试。此类测试包括集成测试,端到端测试以及仅JVM无法验证应用程序功能的其他测试。
  • test目录应包含在本地计算机上运行的测试,例如单元测试。

2.Consider whether to use test doubles考虑是否使用替身测试(test doubles 解释参考:https://www.jianshu.com/p/7a04f28b08a6)

创建测试时,您可以选择创建真实对象或测试替身,例如假对象或模拟对象。通常,在测试中使用真实对象比使用测试替身更好,尤其是当测试对象满足以下条件之一时:

  • 该对象是一个数据对象。
  • 除非它与依赖项的真实对象版本通信,否则该对象无法运行。一个很好的例子是事件回调处理程序。
  • 使用依赖项复制对象的通信很困难。一个很好的例子是SQL数据库处理程序,其中真实数据库比伪造的数据库能够提供更健壮的测试。

但是,如果您的测试尝试在真实对象上执行以下类型的操作,则最好创建伪造或甚至模拟对象 fake or mock:

  • 长操作,例如处理大文件。
  • 非密封操作Non-hermetic actions,例如连接到任意开放端口。
  • 难以创建的配置。

3.android中的测试类型:

  金字塔模型,分别是unitTest单元测试(70%) ,integration tests集成测试(20%),UI test(10%)

  官方推荐使用Robolectric和AndroidJUnitTest进行单元测试,参考官网http://robolectric.org/

  unit test:可以一次验证一个类的应用程序行为。

  integration test:validate either interactions between levels of the stack within a module, or interactions between related modules.用来验证一个模块中堆栈级别的交互,或者不同模块中的交互

Use your app's structure and the following examples of medium tests (in order of increasing scope) to define the best way to represent groups of units in your app:

  1. Interactions between a view and view model, such as testing a Fragment object, validating layout XML, or evaluating the data-binding logic of a ViewModel object.视图和视图模型之间的交互,例如测试 Fragment 对象,验证布局XML或评估对象的数据绑定逻辑 ViewModel
  2. Tests in your app's repository layer, which verify that your different data sources and data access objects (DAOs) interact as expected.在应用程序的存储库层中进行测试,以验证您的不同数据源和数据访问对象(DAO)是否按预期进行交互。
  3. Vertical slices of your app, testing interactions on a particular screen. Such a test verifies the interactions throughout the layers of your app's stack.应用程序的垂直切片,测试特定屏幕上的交互。此类测试会验证应用程序堆栈各层的交互。
  4. Multi-fragment tests that evaluate a specific area of your app. Unlike the other types of medium tests mentioned in this list, this type of test usually requires a real device because the interaction under test involves multiple UI elements.多片段测试,用于评估应用的特定区域。与此列表中提到的其他类型的介质测试不同,此类测试通常需要真实设备,因为测试中的交互涉及多个UI元素。

具体执行方式:

  1. Use methods from the Espresso Intents library. To simplify the information that you're passing into these tests, use fakes and stubbing.
  2. Combine your use of IntentSubject and Truth-based assertions to verify the captured intents.

  官方推荐使用espresso进行集成测试:https://developer.android.google.cn/training/testing/espresso/intents

  UI test:end-to-end tests that validate user journeys spanning multiple modules of your app.验证用户遍历应用中的不同模块。

  具体模型的介绍参考视频:https://www.youtube.com/watch?v=pK7W5npkhho&start=111

二、单元测试具体实践:

1、junit实践 (官方推荐使用Truth断言替代junit断言http://truth.dev/,我用不熟,暂时没管)

gradle添加依赖包,并且再AndroidManifest.xml中引入对应的lib,添加的包是根据junit的对应的用途,如果有些不会用到,可以不添加,具体对应关系参考:https://developer.android.google.cn/training/testing/set-up-project#junit-based-libs

 编辑depedency: 

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'

在项目src/com...../test 目录下新建junit的用例:

package com.patech.testApp;

import org.junit.Test;

import static org.junit.Assert.assertTrue;

public class JunitTest {
@Test
public void testJunitTrue(){
assertTrue(1==1);
}
@Test
public void testJunitFalse(){
assertTrue(1==2);
}
}

测试结果应该是testJunitTrue pass,testJunitFalse failure。

这里用得依旧是junit的断言,可以更改为truth的断言,增加对应depenency,然后执行例子。

testImplementation "com.google.truth:truth:1.0"

  

public class TruthTest {
@Test
public void truthTestTrue(){
String string = "awesome";
assertThat(string).startsWith("awe");
assertWithMessage("Without me, it's just aweso").that(string).contains("me"); }
@Test
public void truthTestFalse(){
String string = "awesome";
assertThat(string).startsWith("awe.");
assertWithMessage("Without me, it's just aweso").that(string).contains("mex");
}
}

  

2、

  • 如果您对Android框架有依赖关系,特别是那些与框架创建复杂交互的框架,那么最好 使用Robolectric 包含框架依赖关系
  • 如果您的测试对Android框架的依赖性最小,或者测试仅依赖于您自己的对象,那么使用像Mockito这样的模拟框架来 包含模拟依赖项是很好的。

Robolectric的单元测试

添加gradle依赖:

androidImplementation "org.robolectric:robolectric:3.6.1"

  

添加其他配置

android {
// Robolectric
testOptions {
unitTests.includeAndroidResources = true
}
}

  

编写测试用例,保存再androidTest包中:

import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Test; import static com.google.common.truth.Truth.assertThat; public class UnitTestSampleJava {
private static final String FAKE_STRING = "HELLO_WORLD";
private Context context = ApplicationProvider.getApplicationContext(); @Test
public void readStringFromContext_LocalizedString() {
// Given a Context object retrieved from Robolectric...
ClassUnderTest myObjectUnderTest = new ClassUnderTest(context); // ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString(); // ...then the result should be the expected one.
assertThat(result).isEqualTo(FAKE_STRING);
}
}

  

执行测试,需要连接手机或者模拟器。

3、Mockito

添加gradle依赖:

// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:1.10.19'

  

编写用例,保存再test包中

import android.content.Context;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class)
public class UnitTestSample { private static final String FAKE_STRING = "HELLO WORLD"; @Mock
Context mockContext; @Test
public void readStringFromContext_LocalizedString() {
// Given a mocked Context injected into the object under test...
when(mockContext.getString(R.string.hello_world))
.thenReturn(FAKE_STRING);
ClassUnderTest myObjectUnderTest = new ClassUnderTest(mockContext); // ...when the string is returned from the object under test...
String result = myObjectUnderTest.getHelloWorldString(); // ...then the result should be the expected one.
assertThat(result, is(FAKE_STRING));
}
}

 

 

Android 测试-Robolectric,mockito,esspresso的更多相关文章

  1. Android测试:Testing Apps on Android

    原文:https://developer.android.com/training/testing/index.html 测试你的App是开发过程中的重要组成部分.通过对应用程序持续的运行测试,你可以 ...

  2. Android测试:Fundamentals of Testing

    原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...

  3. Android测试(二):Android测试基础

    原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...

  4. Android测试(一):在Android中测试App

    原文:https://developer.android.com/training/testing/index.html 测试你的App是开发过程中的重要组成部分.通过对应用程序持续的运行测试,你可以 ...

  5. 1、Android测试入门

    编写和运行测试时Android APP开发周期中的重要的一环.好的测试可以让你非常容易的在开发过程中发现bug,提升你对自己代码的自信.使用Android Studio,你可以在物理设备或者虚拟机中运 ...

  6. Android测试:从零开始2——local单元测试

    上一篇分析了android项目的测试分类,这一篇讲local单元测试. 参考android官方文档. 测试前需要配置测试环境,新建项目后,目录下会出现app/src/test/java/文件夹,这个文 ...

  7. 2014 非常好用的开源 Android 测试工具

    http://www.php100.com/html/it/mobile/2014/1015/7495.html 当前有很大的趋势是转向移动应用平台,Android 是最广泛使用的移动操作系统,201 ...

  8. Android测试提升效率批处理脚本(三)

    前言: 前面放出过几次批处理,这次只放一个环境检查的被管理员给打回来了,不得不再找找几个有含金量的放出来,请看正文~~~ 目录 1.Android环境检查 2.Android内存监控 3.模拟蓝牙手柄 ...

  9. Android测试基础题(三)

    今天接着给大家带来的是Android测试基础题(三).    需求:定义一个排序的方法,根据用户传入的double类型数组进行排序,并返回排序后的数组 俗话说的好:温故而知新,可以为师矣 packag ...

随机推荐

  1. OneNote中更改英文输入默认不是微软雅黑的问题

    win10下的终极版解决方案: 1.进入C:\Windows\Fonts找到Calibri字体,点进去后先右键Calibri常规-属性-安全-高级,将所有者从“TrustedInstaller”更改为 ...

  2. 第07组 Alpha冲刺(4/4)

    队名:秃头小队 组长博客 作业博客 组长徐俊杰 过去两天完成的任务:学习了很多东西 Github签入记录 接下来的计划:继续学习 还剩下哪些任务:后端部分 燃尽图 遇到的困难:自己太菜了 收获和疑问: ...

  3. C++用于类型转换的4个操作符

    Dynamic_cast,   const_cast,  static_cast,  reinterpret_cast. (1)reinterpret_cast 用于基本的类型转换.如 in *ip; ...

  4. mysql navcat备份使用详解

    mysql navcat备份使用详解 点击备份 然后新建备份 然后选择要备份的表 就可以了 以后这个表删除了 内容变更了 都可以点击 还原备份就可以了

  5. js原生导出excel和csv

    ​ 严格意义来说并不是真正的excel文件,只是可以用excel打开查看而已,实际上的格式是逗号分隔文件即csv文件. 这里有几个坑要说一下: 不加Unicode的utf8头部标识excel打开文件会 ...

  6. 关于time_wait状态的理解

    TIME_WAIT状态之所以存在,是为了保证网络的可靠性 有以下原因: 1.为实现TCP全双工连接的可靠释放    当服务器先关闭连接,如果不在一定时间内维护一个这样的TIME_WAIT状态,那么当被 ...

  7. oracle的jdbc的版本与jdk对应关系

    连接类型:1. JDBC OCI: oci是oracle call interface的缩写,此驱动类似于传统的ODBC 驱动.因为它需要Oracle Call Interface and Net8, ...

  8. NOP法破解

    目录 步骤 步骤 OD载入目标软件,汇编窗口右键搜索字符串,发现错误类提示字符串,双击该字符串来到该段代码位置. 向上寻找到跳转到本段错误提示代码的跳转指令,用NOP指令填充跳转指令. 保存修改后的代 ...

  9. python pip命令安装相当于yum仓库

    进入pip目录: 创建pip.conf: 打开pip.conf [global] index-url=https://mirrors.aliyun.com/pypi/simple/ trusted-h ...

  10. (转)基于FFPMEG2.0版本的ffplay代码分析

    ref:http://zzhhui.blog.sohu.com/304810230.html 背景说明 FFmpeg是一个开源,免费,跨平台的视频和音频流方案,它提供了一套完整的录制.转换以及流化音视 ...