转载gradleforandroid第六篇(测试)

wust小吴 wust小吴     2022-08-01     666

关键词:

由于现阶段Android开发趋于敏捷开发,再加上国内大大小小的互联网公司都在做app,导致很多这会是一个系列,所以如果你看完这篇文章,请看下列文章:

开发人员对单元测试没有基本的概念,但是本篇博文不会为大家讲解什么是单元测试,功能测试,而是讲解如何在Android studio上利用gradle使用现阶段流行的测试框架等。

为了确保app或者library库的质量,有一个完整的测试非常重要。很长一段时间,Android开发工具都缺乏针对完整性测试的支持,但是最近,google为之做了大量的工作,其让开发者做测试变得更加容易了,一些旧的框架更新了版本,新的框架也被加入进来。我们现在不仅可以在Android studio中运行这些测试,甚至可以用gradle通过命令行直接执行。

所以基于此,我们这一章,将会为大家介绍几种测试Android app的方式,我们也会深究之为何gradle可以帮助测试自动化。

这一章节我将遵循以下内容:

  • 单元测试
  • 功能测试
  • 测试覆盖率

单元测试

相信大家都有了单元测试的概念,那么好的单元测试不仅仅能够确保app的质量,同时还可以让新代码开发更加容易。Android studio和gradle android插件默认支持单元测试,但是在你使用它之前,你仍需配置一下。

JUnit

JUnit存活了若干年,在测试界非常流行。其使得测试代码容易编写和维护,但是记住,JUnit只能测试逻辑代码,针对和Android SDK相关的代码并没什么卵用。

在你开始编写junit测试之前,你需要为其新建一个目录。通常呢,这个会被叫做test,其会和你的main文件夹平级。

app
└─── src
├─── main
│ ├─── java
        │    │    └─── com.example.app
        │    └───res
        └─── test
             └─── java
                  └─── com.example.app

你可以在test目录下创建测试类。

我建议你使用JUnit 4,你可以将其作为依赖添加到你的依赖库。

dependencies {
       testCompile ‘junit:junit:4.12‘
}

注意到你使用了testCompile,这意味着该jar包只会在你测试的时候导入apk。

如果你有其他的构建版本呢,而你又只是想为特定版本添加该jar,你只需要这么做:

dependencies {
       testPaidCompile ‘junit:junit:4.12‘
 }

当所有的事情都OK了,就是时候开始写测试代码了。下面是简单的测试代码:

import org.junit.Test;
   import static org.junit.Assert.assertEquals;
   public class LogicTest {
       @Test
       public void addingNegativeNumberShouldSubtract() {
           Logic logic = new Logic();
           assertEquals("6 + -2 must be 4", 4, logic.add(6, -2));
           assertEquals("2 + -5 must be -3", -3, logic.add(2, -5));
       }
}

那么如何跑起来呢,也很简单,运行gradlew test。如果你只是想再特定版本中跑呢,那就加一个呗gradlew testDebug。如果测试失败,gradle将会打印相关错误,如果所有测试成功通过,那么会显示BUILD SUCCESSFUL 。

可能你会说,单个测试用例导致整个测试失败,这样不好,如果你想把整个测试案例都跑一遍,那也很简单啊:

$ gradlew test --continue

执行测试任务不仅仅是跑完所有的测试,而且其还会为你创建一份测试报告,你可以找到它app/build/reports/tests/debug/index.html。这份报告让你能够更快的发现问题,我觉得最重要的是当你将你的测试自动化后,这会非常有用,gradle会为每个构建版本都创建一份测试报告。如果你执行测试成功,你的测试报告会是这个样子:

说了这么多原始的做法,那么看看Android studio怎么运行测试的吧。右键项目或者选择开始按钮。。这个太基础不多说了,运行成功是这个样子:

好了,junit测试讲完了,是不是很简单。

如果你想测试你的关联Android sdk代码怎么办,单元测试不是一个好主意,幸运的是,有多个依赖包供你选择,其中最出名的是Robolectric,其可以让你更方便的测试Android功能,并且还不用在设备或者模拟器上运行。

Robolectric

通过使用Robolectrie,你可以编写测试类,这些类可以使用Android SDK和资源文件,当然其还是跑在jvm上,这会让你测试app更加迅速。

在开始使用Robolectrie之前,你需要添加依赖。注意除了Robolectric依赖,你需要添加JUnit包。

apply plugin: ‘org.robolectric‘
   dependencies {
       compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
       compile ‘com.android.support:appcompat-v7:22.2.0‘
       testCompile ‘junit:junit:4.12‘
       testCompile‘org.robolectric:robolectric:3.0‘
       testCompile‘org.robolectric:shadows-support:3.0‘
}

Robolectrie测试类也需要写在test文件夹下,举个例子:

 @RunWith(RobolectricTestRunner.class)
   @Config(manifest = "app/src/main/AndroidManifest.xml", sdk = 18)
   public class MainActivityTest {
       @Test
       public void clickingButtonShouldChangeText() {
           AppCompatActivity activity = Robolectric.buildActivity
             (MainActivity.class).create().get();
           Button button = (Button)
             activity.findViewById(R.id.button);
           TextView textView = (TextView)
             activity.findViewById(R.id.label);
           button.performClick();
           assertThat(textView.getText().toString(), equalTo
             (activity.getString(R.string.hello_robolectric)));
        } 
    }

功能测试

神马是功能测试,其是用来测试一个app的多个模块是否能够正常工作。举个栗子,你可以创建一个功能测试来确保你点击某一按钮后是否会有一个新的activity。依然,我们会有很多框架。但是在这里,我推荐Espresso。

Espresso

google创建Espresso的目的就是在于简化开发人员编写功能测试用例。这个包是由Android support repository提供,所以你可以通过SDK Manager使用它。

在运行测试用例之前,你需要定义一个runner。google提供了AndroidJUnitRunner测试runner,这将帮助你在手机上运行Unit测试。测试runner可以帮你安装apk以及一个测试apk,执行所有测试,生成测试报告。

假设你下载了support library包,那么你需要这么定义:

defaultConfig {
       testInstrumentationRunner
         "android.support.test.runner.AndroidJUnitRunner"
   }

当然你需要添加一些依赖包:

 dependencies {
       compile fileTree(dir: ‘libs‘, include: [‘*.jar‘])
       compile ‘com.android.support:appcompat-v7:22.2.0‘
       androidTestCompile ‘com.android.support.test:runner:0.3‘
       androidTestCompile ‘com.android.support.test:rules:0.3‘
       androidTestCompile
         ‘com.android.support.test.espresso:espresso-core:2.2‘
       androidTestCompile
         ‘com.android.support.test.espresso:espresso-contrib:2.2‘
   }

注意到这些依赖包使用了androidTestCompile,其不同于testCompile。当你直接运行时,会报错:

Error: duplicate files during packaging of APK app-androidTest.apk
     Path in archive: LICENSE.txt
     Origin 1: .../hamcrest-library-1.1.jar
     Origin 2: .../junit-dep-4.10.jar

其意思也很清楚,因为多个文件导致,你可以简单处理下:

 android {
     packagingOptions {
     exclude ‘LICENSE.txt‘
  }
}

注意:功能测试需要放在AndroidTest目录下,下面是测试用例:

@RunWith(AndroidJUnit4.class)
   @SmallTest
   public class TestingEspressoMainActivityTest {
       @Rule
       public ActivityTestRule<MainActivity> mActivityRule = new
         ActivityTestRule<>(MainActivity.class);
       @Test
       public void testHelloWorldIsShown() {
           onView(withText("Hello world!")).check
             (matches(isDisplayed()));
        } 
    }

功能测试也有测试报告,当正确执行后,应该是这样的:

最后可能有朋友问,在Android studio中执行测试,那就附图吧:

测试覆盖率

一旦你在你的项目中使用到了测试,那么你肯定想知道你的测试覆盖量。很真实,依然有很多测试覆盖率工具,我推荐的是Jacoco。

Jacoco

有一份覆盖率报告,很简单。你只需要配置一下:

buildTypes {
     debug {
       testCoverageEnabled = true
     }
}

当你执行完构建,你可以在app/build/ outputs/reports/coverage/debug/index.html中找到,每个版本都会有一个报告。测试覆盖率会是这样的:

你甚至可以通过点击查看更多信息,可以看到哪一行代码被测试。

总结

在这一章,我们学习了如何测试,我们学习了简单的单元测试,以及Robolectric测试。我们学习了功能测试,以及学习了如何使用Espresso。最好,我们学会了如何查看测试覆盖率报告。

在下一章,我将会带来最重要的一章,即自定义化构建过程,创建自定义tasks和插件。当然了我们会首先介绍Groovy语法,理解其语法让你能够更轻松的理解gradle是如何工作的。

转载gradleforandroid第四篇(构建变体)

当你在开发一个app,通常你会有几个版本。大多数情况是你需要一个开发版本,用来测试app和弄清它的质量,然后还需要一个生产版本。这些版本通常有不同的设置,例如不同的URL地址。更可能的是你可能需要一个免费版和收费... 查看详情

接口测试(java+testng+ant+jenkins)第六篇testng二

1、testng中,多次执行用例  @Test(dataProvider="data-provider")  在@Test标签后面加上参数来源:dataProvider(data-provider)   data-provider中有多少组数据,@Test就会使用数据执行多少次2、dataProvider的配置和使用@DataProvider(name="data-p... 查看详情

第六篇scrum冲刺博客

一、DailyScrumMeeting照片二、每个人的工作成员ItemID已完成工作明天计划完成的工作遇到的困难张鸿o1已完成工作,实现积分变换,碰撞检测将其他剩余功能进行整合结束场景的生成夏浚杰o2将昨天写的代码出现的漏洞补上将整体代... 查看详情

区块链-前端交互第六篇:以太测试网转账和gas计算(代码片段)

文章目录Gas费用部分变量说明转账Gas计算公式以太测试网Goerli测试网Sepolia测试网测试网单笔转账(弄清Gas费用)不设置Gas进行转账设置Gas进行转账:web3-eth报错Error:eip-1559transactiondonotsupportgasPriceGas费用参考文章:... 查看详情

webpack系列第六篇:如何编写loader(代码片段)

...欢迎点赞关注。写作不易,未经作者同意,禁止任何形式转载!!!关于WebpackLoader,网上已经有很多很多的资料,很难讲出花来,但是要写Webpack的系列博文又没办法绕开这一点,所以我阅读了超过20个开源项目,尽量全面地总... 查看详情

构建之法—第六篇

这周的学习关于典型用户和场景。VisualStudio是一个非常成功的软件开发集成环境,支持项目管理,测试工具,以及第三方的插件。对于定义典型用户,我们有不同的需求:受欢迎的典型用户和不受欢迎的典型用户,其中,受欢迎... 查看详情

第六篇:面向对象

第六篇:面向对象  PYTHON-面向对象类绑定方法PYTHON-面向对象继承派生PYTHON-面向对象-练习-王者荣耀对砍游戏  查看详情

第六篇vggnet——模型精讲

文章目录 查看详情

数据结构第六篇——顺序存储结构与链式存储结构的特点

?注:未经博主同意,不得转载。两者特点:顺序表的特点是逻辑上相邻的数据元素,物理存储位置也相邻,并且,顺序表的存储空间需要预先分配。它的优点:  (1)方法简单,各种高级语言中都有数组,容易实现。  (2... 查看详情

用仿actionscript的语法来编写html5——第六篇,textfield与输入框

一,对比1,html5中首先看看在html5的canvas中的文字显示varcanvas=document.getElementById("myCanvas");varcontext=canvas.getContext("2d");context.font="40ptCalibri";context.fillStyle="#0000ff";context.fillText("文字测试!",50,1 查看详情

kubernetes第六篇:k8s持久化存储(亲测可用)(代码片段)

文章目录一、前言二、volumes实现本地持久化存储2.1K8S各个Pod之间可以存储和网络的共享2.2volumes实现本地持久化存储三、远程服务器持久化存储3.1PersistentVolume3.2PersistentVolumeClaim3.3Pod中如何使用PVC(Pod绑定PVC)3.4远程服务器持久化存... 查看详情

kubernetes第六篇:k8s持久化存储(亲测可用)(代码片段)

文章目录一、前言二、volumes实现本地持久化存储2.1K8S各个Pod之间可以存储和网络的共享2.2volumes实现本地持久化存储三、远程服务器持久化存储3.1PersistentVolume3.2PersistentVolumeClaim3.3Pod中如何使用PVC(Pod绑定PVC)3.4远程服务器持久化存... 查看详情

第六篇抽屉效果+uitabbarcontroller

依赖于第三方的框架RESideMenu1.AppDelegate.m中的实现-(BOOL)application:(UIApplication*)applicationdidFinishLaunchingWithOptions:(NSDictionary*)launchOptions{//Overridepointforcustomizationafterapplicationlaunch.//在 查看详情

关于ajax第六篇

使用回调函数回调函数是一种以参数形式传递给另一个函数的函数。如果您的网站上存在多个AJAX任务,那么您应该为创建XMLHttpRequest对象编写一个标准的函数,并为每个AJAX任务调用该函数。该函数调用应该包含URL以及发生onreadys... 查看详情

第六篇avplayer地址视频播放控件

1.引用头文件#importAVFoundation2.自定义AVPlayer(播放的机器)3.自定义AVPlayerItem(胶片)>>视频的URL转成AVAsset4.AVPlayerLayer(白板)  查看详情

第六篇elasticsearchexpress删除索引数据

express框架删除elasticsearch索引数据1.在elasticsearch.js文件下添加functiondeleteDocument(id){returnelasticClient.delete({index:indexName,type:"foods",id:id});}exports.deleteDocument=deleteDocument;2.在路由删除数据代码块中添加el 查看详情

第六篇io流技术(代码片段)

packagecom.zzp.demo01;importjava.io.ByteArrayInputStream;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.InputStream;/****四 查看详情

android插件化开发——hook方式第六篇

http://blog.csdn.net/u013022222/article/details/51295208 查看详情