添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

关于单元测试,在维基百科中,给出了如下定义:

在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
android中的单元测试基于JUnit,可分为本地测试和instrumented测试,在项目中对应

一般Android项目中的测试目录结果如下:

  • module-name/src/test/java/.
    该目录下的代码运行在本地JVM上,其优点是速度快,不需要设备或模拟器的支持,但是无法直接运行含有android系统API引用的测试代码。
  • module-name/src/androidTest/java/.
    该目录下的测试代码需要运行在android设备或模拟器下面,因此可以使用android系统的API,速度较慢。
    在这里插入图片描述

以上分别执行在JUnit和AndroidJUnitRunner的测试运行环境,两者主要的区别 在于是否需要android系统API的依赖
在实际开发过程中,我们应该尽量用JUnit实现本地JVM的单元测试,而项目中的代码大致可分为以下三类:

  • 强依赖关系,如在Activity,Service等组件中的方法,其特点是大部分为private方法,并且与其生命周期相关,无法直接进行单元测试,可以进行Ecspreso等UI测试。
  • 部分依赖,代码实现依赖注入,该类需要依赖Context等android对象的依赖,可以通过Mock或其它第三方框架实现JUnit单元测试或使用androidJunitRunner进行单元测试。
  • 纯java代码,不存在对android库的依赖,可以进行JUnit单元测试

常用的测试框架

在android测试框架中,常用的有以下几个框架和工具类:

  1. JUnit4:Java最常用的单元测试框架
  2. AndroidJUnitRunner:适用于 Android 且与 JUnit 4 兼容的测试运行器
  3. Mockito:Mock测试框架
  4. Espresso:UI 测试框架;适合应用中的功能性 UI 测试
  5. UI Automator:UI 测试框架;适合跨系统和已安装应用的跨应用功能性 UI 测试

关于单元测试框架的选择,可以参考下图:

Junit4

JUnit4是一套基于注解的单元测试框架。在android studio中,编写在test目录下的测试类都是基于该框架实现,该目录下的测试代码运行在本地的JVM上, 不需要设备(真机或模拟器)的支持
JUnit4中常用的几个注解:

在test下添加测试类,对于需要进行测试的方法添加@Test注解,在该方法中使用assert进行判断,示例如下。

package com.selflearning.testdemo;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class SMSUtilTest {
    private static SMSUtil smsUtil;
    @BeforeClass
    public static void initSMSUtil() {
        smsUtil = new SMSUtil();
    @Test
    public void testGetOTPFromSMS() {
        String otp = smsUtil.getOTPFromSMS("verification code:123456", 6);
        assertEquals("123456", otp);
    @AfterClass public static void quitTest() {
        smsUtil = null;

当需要传入多个参数进行条件覆盖时,可以使用@Parameters来进行单个方法的多次不同参数的测试,使用该方法需要如下步骤:

  1. 在测试类上添加@RunWith(Parameterized.class)注解。
  2. 添加构造方法,并将测试的参数作为其构造参数。
  3. 添加获取参数集合的static方法,并在该方法上添加@Parameters注解。
  4. 在需要测试的方法中直接使用成员变量,该变量由JUnit通过构造方法生成。
package com.selflearning.testdemo;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)//1.在测试类上添加@RunWith(Parameterized.class)注解。
public class SMSUtilWithParametersTest {
    private String sms;
    private String expectResult;
    private static SMSUtil smsUtil;
    //2.添加构造方法,并将测试的参数作为其构造参数
    public SMSUtilWithParametersTest(String sms, String expectResult) {
        this.sms = sms;
        this.expectResult = expectResult;
    //3.添加获取参数集合的static方法,并在该方法上添加@Parameters注解
    @Parameterized.Parameters
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { "test123456", "123456" },
                { "test111111haha", "111111" },
                { "verfication code is:122", null },
                { "verifcation code is:123456789, from myimy", null }});
    @BeforeClass public static void initSMSUtil() {
        smsUtil = new SMSUtil();
    @Test public void testGetOTPFromSMS() {
        //4.在需要测试的方法中直接使用成员变量,该变量由JUnit通过构造方法生成
        String otp = smsUtil.getOTPFromSMS(sms, 6);
        assertEquals(expectResult, otp);
    @AfterClass public static void quitTest() {
        smsUtil = null;

当然也可以通过注解的方式初始化变量,代码如下:

@RunWith(Parameterized.class)//1.在测试类上添加@RunWith(Parameterized.class)注解。
public class SMSUtilWithParametersTest {
    @Parameterized.Parameter(0)
    public String sms; //sms用data()中索引为0的数据初始化,注意变量访问控制权限必须为public
    @Parameterized.Parameter(1)
    public String expectResult;
    private static SMSUtil smsUtil;
    //3.添加获取参数集合的static方法,并在该方法上添加@Parameters注解
    @Parameterized.Parameters
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { "test123456", "123456" },
                { "test111111haha", "111111" },
                { "verfication code is:122", null },
                { "verifcation code is:123456789, from myimy", null }});
    @BeforeClass public static void initSMSUtil() {
        smsUtil = new SMSUtil();
    @Test public void testGetOTPFromSMS() {
        //4.在需要测试的方法中直接使用成员变量,该变量由JUnit通过构造方法生成
        String otp = smsUtil.getOTPFromSMS(sms, 6);
        assertEquals(expectResult, otp);
    @AfterClass public static void quitTest() {
        smsUtil = null;

如果我们只想同时运行几个测试类,如某一类功能的测试代码,该如何办呢?没问题,JUnit提供了Suite注解,在对应的测试目录下创建一个空Test类,并该类上添加如下注解:

  • @RunWith(Suite.class):配置Runner运行环境
  • @Suite.SuiteClasses({A.class, B.class}):添加需要一起运行的测试类

示例如下:

package com.selflearning.testdemo;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({SMSUtilWithParametersTest.class, SMSUtilTest.class})
public class SuitTest {

AndroidJUnitRunner

在android开发中,方法中经常使用android系统api,比如Context,Parcelable,SharedPreferences等等。而在本地JVM中(JUnit4)无法调用这些接口,因此,我们就需要使用AndroidJUnitRunner来完成这些方法的测试。使用方法是在androidTest目录下创建测试类,在该类上添加@RunWith(AndroidJUnit4.class)注解。示例如下:

package com.selflearning.testdemo;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class SMSUtilWithContextTest {
    private static Context context;
    private static SMSUtil smsUtil;
    @BeforeClass public static void setup(){
        context = InstrumentationRegistry.getContext();
        smsUtil = new SMSUtil();
    @Test public void testHasSMSReceivePermission() {
        Assert.assertFalse(smsUtil.hasSMSReceivePermission(context));

使用AndroidJUnitRunner最大的缺点在于无法在本地JVM运行,直接的结果就是测试速度慢,同时无法执行覆盖测试,因此在实际工作中很少使用到该种测试。因此出现了很多替代方案,比如在设计合理,依赖注入实现的代码,可以使用Mockito来进行本地测试。

Mockito

Mockito是一个Mock框架,也是Java中使用比较广泛的一个Mock框架。关于Mock的概念,其实很简单:所谓的mock就是创建一个类的虚假的对象,在测试环境中,用来替换掉真实的对象,以达到以下目的:

  • 验证这个对象的某些方法的调用情况,调用了多少次,参数是什么等等
  • 指定这个对象的某些方法的行为,返回特定的值,或者是执行特定的动作
  • 可以在开发机上测试,而不用在Android模拟器或物理机上测试(At runtime, tests will be executed against a modified version of android.jar where all final modifiers have been stripped off.)

关于Mock的使用需要注意以下两点:

  • Mockito最终mock出来的是一个类的对象,而类本身并不会改变。如下代码:
Context context;
private Context mockContext() {
    when(context.checkPermission(eq("android.permission.RECEIVE_SMS"), anyInt(), anyInt())).thenReturn(0);
    return context;

如果这里我们在mockContext()中直接返回一个new Context();在实际测试中依然会报错。

  • mock出来的对象并不会自动替换掉正式代码里面的对象,你必须要有某种方式把mock对象应用到正式代码里面,如构造注入或setter注入。

Mockito的测试需要在build.gradle做如下修改:

dependencies {
  testCompile 'junit:junit:4.12'
  testCompile "org.mockito:mockito-core:1.9.5"

对于一些不想mock的类和方法,Mockito也提供了方法,官方文档是这样说的:
“Method … not mocked.”
The android.jar file that is used to run unit tests does not contain any actual code - that is provided by the Android system image on real devices. Instead, all methods throw exceptions (by default). This is to make sure your unit tests only test your code and do not depend on any particular behaviour of the Android platform (that you have not explicitly mocked e.g. using Mockito). If that proves problematic, you can add the snippet below to your build.gradle to change this behavior:

android {
  // ...
  testOptions { 
    unitTests.returnDefaultValues = true

We are aware that the default behavior is problematic when using classes like Log or TextUtils and will evaluate possible solutions in future releases.
如下是我个人写的完整的测试用例,由于在我们的代码中依赖Android的Context类,因此需要用Mockito mock一个Context类的对象。

package com.selflearning.testdemo;
import android.content.Context;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.when;
import static org.mockito.Matchers.eq;
@RunWith(MockitoJUnitRunner.class)
public class SMSUtilWithMockitTest {
    @Mock
    private static Context context;
    private static SMSUtil smsUtil;
    @BeforeClass
    public static void setup() {
        smsUtil = new SMSUtil();
    @Test
    public void testHasSMSReceivePermission() {
        assertTrue(smsUtil.hasSMSReceivePermission(mockContext()));
    private Context mockContext() {
        when(context.checkPermission(eq("android.permission.RECEIVE_SMS"), anyInt(), anyInt())).thenReturn(0);
        return context;

Espresso

Espresso 测试框架提供了一组 API 来构建 UI 测试,用于测试应用中的用户流(要求 Android 2.2(API 级别 8)或更高版本)。利用这些 API,可以编写简洁、运行可靠的自动化 UI 测试。Espresso 非常适合编写白盒自动化测试,其中测试代码将利用所测试应用的实现代码。
Espresso 测试框架的主要功能包括:

  • 灵活的 API,用于目标应用中的视图和适配器匹配。
  • 一组丰富的操作 API,用于自动化 UI 交互。
  • UI 线程同步,用于提升测试可靠性。

利用 Espresso.onView() 方法,您可以访问目标应用中的 UI 组件并与之交互。此方法接受 Matcher 参数并搜索视图层次结构,以找到符合给定条件的相应 View 实例。您可以通过指定以下条件来优化搜索:

例如,要找到 ID 值为 my_button 的按钮,可以指定如下匹配器:

onView(withId(R.id.my_button));

如果搜索成功,onView() 方法将返回一个引用,让您可以执行用户操作并基于目标视图对断言进行测试。

适配器匹配

在 AdapterView 布局中,布局在运行时由子视图动态填充。如果目标视图位于某个布局内部,而该布局是从 AdapterView(例如 ListView 或 GridView)派生出的子类,则 onView() 方法可能无法工作,因为只有布局视图的子集会加载到当前视图层次结构中。因此,请使用 Espresso.onData() 方法访问目标视图元素。Espresso.onData() 方法将返回一个引用,让您可以执行用户操作并根据 AdapterView 中的元素对断言进行测试。

操作 API

通常情况下,可以通过根据应用的用户界面执行某些用户交互来测试应用。借助 ViewActions API,可以轻松地实现这些操作的自动化。您可以执行多种 UI 交互,例如:

  • 视图点击
  • 滑动
  • 按下按键和按钮
  • 键入文本
  • 打开链接

例如,要模拟输入字符串值并按下按钮以提交该值,可以像下面一样编写自动化测试脚本。ViewInteraction.perform() 和 DataInteraction.perform() 方法采用一个或多个 ViewAction 参数,并以提供的顺序运行操作。

// Type text into an EditText view, then close the soft keyboard
onView(withId(R.id.editTextUserInput))
    .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard());
// Press the button to submit the text change
onView(withId(R.id.changeTextBt)).perform(click());

UI 线程同步

由于计时问题,Android 设备上的测试可能随机失败。此测试问题称为测试不稳定。在 Espresso 之前,解决方法是在测试中插入足够长的休眠或超时期或添加代码,以便重试失败的操作。Espresso 测试框架可以处理 Instrumentation 与 UI 线程之间的同步;这就消除了对之前的计时解决方法的需求,并确保测试操作与断言更可靠地运行。

在Android5.0及以下,使用Espresso启动Activity时或都代码中使用到support包中的其他组件时都会报java.lang.NoClassDefFoundError错误,如下。

java.lang.NoClassDefFoundError: com.selflearning.testdemo.MainActivity
at com.selflearning.testdemo.MainActivityTest.<init>(MainActivityTest.java:24)
......

原因是你的Activity继承了support包里的Activity,如android.support.v7.app.AppCompatActivity。
解决办法是在build.gradle里面加入:

configurations {
    androidTestCompile.exclude group: 'com.android.support', module: 'support-v4'

UI Automator

uiautomatorviewer 工具提供了一个方便的 GUI,可以扫描和分析 Android 设备上当前显示的 UI 组件。您可以使用此工具检查布局层次结构,并查看在设备前台显示的 UI 组件属性。利用此信息,您可以使用 UI Automator(例如,通过创建与特定可见属性匹配的 UI 选择器)创建控制更加精确的测试。

uiautomatorviewer 工具位于 /tools/ 目录中。

访问设备状态

UI Automator 测试框架提供了一个 UiDevice 类,用于在目标应用运行的设备上访问和执行操作。您可以调用其方法来访问设备属性,如当前屏幕方向或显示尺寸。UiDevice 类还可用于执行以下操作:

  • 更改设备旋转
  • 按 D-pad 按钮
  • 按“返回”、“主屏幕”或“菜单”按钮
  • 打开通知栏
  • 对当前窗口进行屏幕截图

例如,要模拟按下“主屏幕”按钮,请调用 UiDevice.pressHome() 方法。

UI Automator API

利用 UI Automator API,可以编写稳健可靠的测试,而无需了解目标应用的实现详情,可以使用这些 API 在多个应用中捕获和操作 UI 组件:

  • UiCollection:枚举容器的 UI 元素以便计算子元素个数,或者通过可见的文本或内容描述属性来指代子元素。
  • UiObject:表示设备上可见的 UI 元素。
  • UiScrollable:为在可滚动 UI 容器中搜索项目提供支持。
  • UiSelector:表示在设备上查询一个或多个目标 UI 元素。
  • Configurator:允许您设置运行 UI Automator 测试所需的关键参数。
package com.selflearning.testdemo;
import android.content.Context;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SdkSuppress;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.widget.Button;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class MainActivityWithUIAutomatorTest {
    private static String APP_NAME = "com.selflearning.testdemo";
    private static final int LAUNCH_TIMEOUT = 5000;
    private UiDevice mUiDevice;
    @Before
    public void startApp() {
        // Initialize UiDevice instance
        mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        // Start from the home screen
        mUiDevice.pressHome();
        // Wait for launcher
        String launcherPkg = mUiDevice.getLauncherPackageName();
        assertNotNull(launcherPkg);
        mUiDevice.wait(Until.hasObject(By.pkg(launcherPkg).depth(0)), LAUNCH_TIMEOUT);
        // Launch the app
        Context context = InstrumentationRegistry.getContext();
        assertNotNull("context is null", context);
        Intent intent = context.getPackageManager().getLaunchIntentForPackage(APP_NAME);
        // Clear out any previous instances
        assertNotNull("intent is null", context);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
        context.startActivity(intent);
        // Wait for the app to appear
        mUiDevice.wait(Until.hasObject(By.pkg(APP_NAME).depth(0)),
                LAUNCH_TIMEOUT);
    @Test
    public void clickButtonTest() throws InterruptedException {
        UiObject editText = mUiDevice.findObject(new UiSelector().resourceId("com.selflearning.testdemo:id/sample_text"));
        if (editText.exists()) {
            try {
                editText.setText("UI Automator");
            } catch (UiObjectNotFoundException e) {
                fail("not found edit text");
        // sleep to see setText result
        Thread.sleep(10000);
        UiObject btn = mUiDevice.findObject(new UiSelector().text("Content").className(Button.class));
        if (btn.exists()) {
            try {
                btn.click();
            } catch (UiObjectNotFoundException e) {
                fail("btn not found");

build.gradle设置

Android 测试支持库的类位于 android.support.test 软件包中。要在 Gradle 项目中使用 Android 测试支持库,请在 build.gradle 文件中添加这些依赖关系:

dependencies {
    testImplementation 'junit:junit:4.12'
    testImplementation 'org.mockito:mockito-core:1.+'
    // Set this dependency to use JUnit 4 rules
    androidTestImplementation 'com.android.support.test:rules:0.3'
    androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:2.2'
    androidTestImplementation "com.android.support:support-annotations:23.3.0"
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    // Set this dependency to build and run Espresso tests
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    androidTestImplementation "org.hamcrest:hamcrest-library:1.3"
    // Set this dependency to build and run UI Automator tests
    androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'

要将 AndroidJUnitRunner 设置为 Gradle 项目中的默认测试仪器运行器,请在 build.gradle 文件中指定此依赖关系:

android {
    defaultConfig {
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  1. Android测试支持库. https://developer.android.google.cn/topic/libraries/testing-support-library/#AndroidJUnitRunner
  2. https://www.jianshu.com/p/925191464389
  3. 测试应用。https://developer.android.com/studio/test/
  4. Unit tests with Mockito - Tutorial. http://www.vogella.com/tutorials/Mockito/article.html
  5. uiautomator-testing. https://developer.android.google.cn/training/testing/ui-testing/uiautomator-testing
单元测试关于单元测试,在维基百科中,给出了如下定义:在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。android中的单元测试... 版权声明:本文版权归微信公众号玉刚说所有,未经许可,不得以任何形式转载 单元测试是应用程序测试策略中的基本测试,通过对代码进行单元测试,可以轻松地验证单个单元的逻辑是否正确,在每次构建之后运行单元测试,可以帮助您快速捕获和修复因代码更改(重构、优化等)带来的回归问题。本文主要聊聊Android中的单元测试单元测试的目的以及测试内容 为什么... 1.1 背景 随着 Android 应用越来越壮大,对应代码量显著增加,代码逻辑也日趋复杂,此时需要采取一定的行动去保证代码质量,减少逻辑漏洞等,于是严格地执行单元测试编写任务,将单元测试落实到平常开发和维护任务当中去,就是很重要的一环,不可忽视。 然而,很多应用开发者之前并未编写过单元测试代码,那么如果有一篇通俗易懂并带有操作步骤的文章,能帮助应用开发者完成从单元测试小白到入门的过渡,就再好不过了,于是本文就是在此情况写就的,如有不好之处,请多多包涵,谢谢...
单元测试创建步骤: 1,创建一个AndroidProject,包名为com.junit.example,类名MainActivity。 这个app只实现一个简单功能:即点击按钮之后,TextView的内容由Hello变为Hello Android。 2,在src目录下添加一个测试包,包名为com.junit.example.test,类名为MainActivityTest
但是在 Kotlin 开发的Android程序中,使用这两个框架真的如在Java中这么好用吗?事实上,许多Kotlin的Android程序员在使用 Mockito 时会遇到一些问题,例如:虽然这上面的问题,都是有解决方法的,但是显而易见的:任何在 Kotlin 上使用 Mockito 进行单元测试的程序员都会踩坑。为什么不提供一个专门针对于 Kotlin 场景下的单元测试呢? 于是就有了 ​​mockk​​。 解决上述出现的问题 支持 Kotlin,包括其语法糖 目前官方文档给出了一些存在的问题:Power
主要是关注对象不一样。黑盒测试主要针对的是程序展现给用户的功能,多用于功能测试,白盒测试主要针对的是程序代码逻辑,多用于单元测试。简单来说,黑盒测试最终展示功能,白盒测试后台代码程序。
一、概述: 使用AndroidTest,我们可以获取到Android运行的环境,并且通过在测试文件中实例化我们需要测试的类,然后自己模拟一些参数去调用实例中的方法,来达到测试代码的目的。一个AndroidTest文件,就相当于一个运行进程一样,可以在真机上运行,并且可以把测试跑后的结果统计出来,作为研发自测重要的一个根据。 二、创建测试单元 我们可以针对我们代码中那些很关键的控制性类创建一个测试单元,这样创建的测试单元就可以包含很多内容。创建的方式也很简单,在需要创建的类边上进入提示,如下: 点击Crea
一.什么是mockito Mockito 是一个强大的用于 Java 开发的模拟测试框架, 通过 Mockito 我们可以创建和配置 Mock 对象, 进而简化有外部依赖的类的测试. 使用 Mockito 的大致流程如下: 创建外部依赖的 Mock 对象, 然后将此 Mock 对象注入到测试类中. 执行测试代码. 校验测试代码是否执行正确.
一、什么是MOCK测试 Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。 Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。 mock中的必知概念: 打桩(存根):模拟要调用的函数(打桩对象),
处于高速迭代开发中的Android项目往往需要除黑盒测试外更加可靠的质量保障,这正是单元测试的用武之地。单元测试周期性对项目进行函数级别的测试,在良好的覆盖率下,能够持续维护代码逻辑,从而支持项目从容应对快速的版本更新。 单元测试是参与项目开发的工程师在项目代码之外建立的白盒测试工程,用于执行项目中的目标函数并验证其状态或者结果,其中,单元指的是测试的最小模块,通常指函数。如图1所示的绿色文件夹即...