热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

简单谈谈androidstudio的单元测试

昨天在完善项目的时候,需要进行单元测试,在Eclipse环境中进行是很简单的,但是在AndroidStudio环境中进行单元测试,在国内找了很多资料,大都是人云亦云,本文发布出来供大家学习参考。

面对android studio Run 一次项目要等好几分钟的痛点,不得不研究一下android studio 的单元测试。

其实我的目的很简单,在不对视图进行操作的前提下,测试一些activity 的生命周期,或网络拉取数据的一些处理,比如解析 json 数据啊,做网络请求啊等等,也就是对 Model层的测试。这些不需要操作视图,但在没有单元测试环境下,比如我们网络请求一些数据,Log 打印看看是否请求成功,却又要 利用模拟器或真机Run 一次项目,花费好几分钟,这是不能容忍的。

于是乎,强大的 android studio 也考虑到了这一点,给我们提供的简单的单元测试类。

让我们来简单的了解学习一下吧。

首先先来了解一下一些名称,方便下面介绍和使用:

在java中咱们有用过 JUnit 的 单元测试 ,那android 也是基于 java 语言编写的,所以也有个 JUnit的单元测试。在做 android 的单元测试需要导入依赖:

androidTestCompile 'junit:junit:4.12'
testCompile 'junit:junit:4.12'

其中, test目录为在本机执行单元测试代码的目录, androidTest为在Android设备上执行单元测试代码的目录。如下图:

Android 自带的 junit单元测试的一些测试类(androidTest测试 需要运行在模拟机或真机上)

1、InstrumentationTestCase框架:

Instrumentation和Activity有点类似,只不过Activity是需要一个界面的,而Instrumentation并不是这样的,我们可以将它理解为一种没有图形界面的,具有启动能力的,用于监控其他类(用Target Package声明)的工具类。

举个例子,利用InstrumentationTestCase 启动一个activity:

在androidTest下新建一个java类,并且继承自InstrumentationTestCase编写一个public void的方法,但是必须要是方法名以test打头,比如testPublishSubject,并不需要@Test注解

public class TestSubject extends InstrumentationTestCase {
  private static final String LOG_TAG = "test";
 
  public void testPublishSubject() {
 
    launchActivity("demo.zts.com.demo",SecondActivity.class,null);
  }
}

2、ApplicationTestCase——测试整个应用程序的类。它允许你注入一个模拟的Context到应用程序中,在应用程序启动之前初始化测试参数,并在应用程序结束之后销毁之前检查应用程序。

使用Context,你可以浏览资源,文件,数据库等等。基类是AndroidTestCase,一般常见的是它的子类,和特定组件关联。

测试代码如下:

public class MyApp extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    String app_name = getResources().getString(R.string.app_name);
    Log.i("MyApp",".........MyApp....app_name.........."+app_name);
  }
}
public class ApplicationTest extends ApplicationTestCase {
  public ApplicationTest() {
    super(MyApp.class);
  }
  public void testStart() {
    String str = null;
    str = mContext.getResources().getString(R.string.app_name);
    Log.i("..",".............ApplicationTest ...........app_name............."+str);
  }

Log 日志:

 07-22 23:27:10.276 32259-32259/demo.zts.com.demo I/MyApp: .........MyApp....app_name..........demo
 07-22 23:27:10.276 32259-32319/demo.zts.com.demo I/TestRunner: started: testStart(demo.zts.com.demo.ApplicationTest)
 07-22 23:27:10.286 32259-32319/demo.zts.com.demo I/..: .............ApplicationTest..........app_name..............demo

3、ActivityUnitTestCase——对单个Activity进行单一测试的类。使用它,你可以注入模拟的Context或Application,或者两者。它用于对Activity进行单元测试。也就是说你可以用于测试单独的activity ,虽然也需要利用模拟机或真机启动,但你启动的只是你需要做测试的activity,于其他activity无关。
测试代码如下:

要测试的 activity

public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    System.out.println("...............MainActivity......onCreate............");
    Log.i("MainActivity","................onCreate............................");

  }
  @Override
  protected void onStart() {
    super.onStart();
    System.out.println("...............MainActivity......onStart............");
    Log.i("MainActivity","................onStart............................");
  }
  @Override
  protected void onStop() {
    super.onStop();
    System.out.println("...............MainActivity......onStop............");
    Log.i("MainActivity","................onStop............................");
  }
  @Override
  protected void onDestroy() {
    super.onDestroy();
    System.out.println("...............MainActivity......onDestroy............");
    Log.i("MainActivity","................onDestroy............................");
  }
}

测试类

public class TestActivity extends ActivityInstrumentationTestCase2 {

  private Context ctx;

  public TestActivity() {
    super(MainActivity.class);
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    ctx = getActivity().getApplicationContext();
  }

  public void testStart() {
    Intent intent = new Intent(ctx, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    ctx.startActivity(intent);
    Log.i("TestActivity","................startActivity............................");

  }

测试 Log 日志:

  * 07-22 23:39:44.146 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onCreate............
     07-22 23:39:44.146 3171-3171/demo.zts.com.demo I/MainActivity: ................onCreate............................
     07-22 23:39:44.151 3171-3171/demo.zts.com.demo D/MZPerfObserver: demo.zts.com.demo onCreate consume 153 ms
     07-22 23:39:44.151 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onStart............
     07-22 23:39:44.151 3171-3171/demo.zts.com.demo I/MainActivity: ................onStart............................
     07-22 23:39:44.326 3171-3171/demo.zts.com.demo D/OpenGLRenderer: Enabling debug mode 0
     07-22 23:39:44.361 3171-3171/demo.zts.com.demo I/System.out: ...............MainActivity......onStop............
     07-22 23:39:44.361 3171-3171/demo.zts.com.demo I/MainActivity: ................onStop............................
 
     07-22 23:39:44.421 3171-3224/demo.zts.com.demo I/TestActivity: ................startActivity............................

还有很多常见的测试,比如ServiceTestCase,ProviderTestCase2等,大家需要慢慢琢磨。

Android 自带的 junit单元测试的一些测试类(test 测试 ,不需要模拟机,电脑直接运行)

比如我需要测试一段java代码,而这段java代码跟android没关系,也就是不用到android的资源,如context,activity 等,说白了就是简单的 java 测试,当然,嘿嘿,android studio也是可以做java代码测试的。

测试代码如下,测试 4+4 等于几:

public class ExampleUnitTest {
  @Test
  public void testAdd() {

    int i = 0;
    i = 4+4;
    System.out.print(".............. "+i);
    Log.i("TAG","..................."+i);
    // 比较 i 是否 等于 8 ,相等的话通过测试!!!
    Assert.assertEquals(8, i);
  }
}

测试成功:

以上测试类的运行是 -点击测试右键 - 选择 RunXXXXX

/*********************华丽分割线***********************/

看了半天好像也没有解决文章最初提到的一个痛点啊,就是我需要测试android的资源,但又不想运行笨重的模拟机或真机,怎么办呢? 妈蛋,被骗了,还钱 -_-、、、 确实,上面提到的测试方法虽然没有解决拜托模拟机测试的痛点,但基于模拟机单元测试的 androidTest 确实方便我们做一些 单独功能的测试,而且能做 UI 测试,因为需要模拟机或真机嘛,所以 UI 或视图测试是没问题的。 还有test 测试,可以做一些不需要android资源的 java代码测试,也是在android开发当中很方便的,不用在启用eclipse 做测试,直接android studio 既可以了。

忽悠,接着 忽悠 -_-////

其实要想脱离 模拟机或真机,又要做使用android资源的测试,如 使用Context,浏览资源,文件,数据库等等。 也是可以的!!! 那 就只有第三方测试框架了 Robolectric

666,你是来做宣传的吗 -_-、、、不过真的很好用,也能很好的解决咱们的痛点。

接下来利用个需求来讲解 Robolectric 测试,免得我忽悠你们。

拿到 android 目录下的 assets 下的json01.txt文件 是一段json数据,让后进行解析,解析后将数据显示。 分析:这个需求就跟android下的资源有关,而咱们利用 Robolectric 做单元测试,并且不需要模拟机或真机的支持。

其中json数据

{
 "name": "coolxing",
 "age": 24,
 "male": true,
 "address": {
  "street": "huiLongGuan",
  "city": "beijing",
  "country": "china"
 }
}

首先需要 Robolectric 依赖,在你的 app module 下注入依赖:

testCompile 'org.robolectric:robolectric:3.0'
注意是 testCompile 而不是 androidTestCompile ,不然你有需要启动模拟器了。并且测试类也是 在 test 下的

测试类:

@RunWith(RobolectricGradleTestRunner.class)
@Config(cOnstants= BuildConfig.class, sdk = 21)
public class MainActivityTest2 {

  @Test
  public void testJson(){
    String str = null;
    str = RuntimeEnvironment.application.getResources().getString(R.string.app_name);

    AssetManager am = null;
    am = RuntimeEnvironment.application.getAssets();
    String strData = null;
    try {
      InputStream inputStream = am.open("json01.txt");
      byte buf[] = new byte[1024];
      inputStream.read(buf);
      strData = new String(buf);
      strData =strData.trim();
      strData.trim();
    } catch (IOException e) {

    }
    jsonBean foo = new Gson().fromJson(strData, jsonBean.class);
    System.out.println("...............json.................."+foo.name);
    System.out.println("...............json.................."+foo.address);
    System.out.println("...............json.................."+foo.age);
  }
}

测试结果:

看,咱们利用application 拿到 android 下的资源,但又不像刚才上面的 androidTestCompile 需要模拟机,是不是很6,我电脑配置比较低,本次测试需要40S多,但不真机快多了。

am = RuntimeEnvironment.application.getAssets();

需要注意几点,类头部需要声明  @ 注解:

@RunWith(RobolectricGradleTestRunner.class)
@Config(cOnstants= BuildConfig.class, sdk = 21)

并且测试方法是以 textxxx() 开头的,如上面的 testJson() ,方法也需要@Test注解!!!
Robolectric 还可以测试 activity ,如:

@RunWith(RobolectricGradleTestRunner.class)
@Config(cOnstants= BuildConfig.class, sdk = 21)
public class MainActivityTest2 {
  @Test
  public void testMainActivity() {

    MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);
    mainActivity.findViewById(R.id.main_tv).performClick();


    Intent expectedIntent = new Intent(mainActivity, SecondActivity.class);

    ShadowActivity openActivity = Shadows.shadowOf(mainActivity);
    Intent actualIntent = openActivity .getNextStartedActivity();

    // Assert.assertEquals(expectedIntent, actualIntent);

  }

其中

MainActivity mainActivity = Robolectric.setupActivity(MainActivity.class);

这句代码就是启动了MainActivity 的生命周期

Robolectric 单元测试类 的 启动 也是跟 上面test 测试类一样,选择 -MainActivityTest2 --右键 -- 选择 Run MainActivityTest2

好了,单元测试就介绍到这里,

其实我也只是初步理解,上面那些基本的也是我做项目的需要我才去学习使用的,还有好多强大的功能大家慢慢探索。


推荐阅读
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Android JSON基础,音视频开发进阶指南目录
    Array里面的对象数据是有序的,json字符串最外层是方括号的,方括号:[]解析jsonArray代码try{json字符串最外层是 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 延迟注入工具(python)的SQL脚本
    本文介绍了一个延迟注入工具(python)的SQL脚本,包括使用urllib2、time、socket、threading、requests等模块实现延迟注入的方法。该工具可以通过构造特定的URL来进行注入测试,并通过延迟时间来判断注入是否成功。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 在Android中解析Gson解析json数据是很方便快捷的,可以直接将json数据解析成java对象或者集合。使用Gson解析json成对象时,默认将json里对应字段的值解析到java对象里对应字段的属性里面。然而,当我们自己定义的java对象里的属性名与json里的字段名不一样时,我们可以使用@SerializedName注解来将对象里的属性跟json里字段对应值匹配起来。本文介绍了使用@SerializedName注解解析json数据的方法,并给出了具体的使用示例。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 本文介绍了一个免费的asp.net控件,该控件具备数据显示、录入、更新、删除等功能。它比datagrid更易用、更实用,同时具备多种功能,例如属性设置、数据排序、字段类型格式化显示、密码字段支持、图像字段上传和生成缩略图等。此外,它还提供了数据验证、日期选择器、数字选择器等功能,以及防止注入攻击、非本页提交和自动分页技术等安全性和性能优化功能。最后,该控件还支持字段值合计和数据导出功能。总之,该控件功能强大且免费,适用于asp.net开发。 ... [详细]
  • 本文介绍了互联网思维中的三个段子,涵盖了餐饮行业、淘品牌和创业企业的案例。通过这些案例,探讨了互联网思维的九大分类和十九条法则。其中包括雕爷牛腩餐厅的成功经验,三只松鼠淘品牌的包装策略以及一家创业企业的销售额增长情况。这些案例展示了互联网思维在不同领域的应用和成功之道。 ... [详细]
  • express工程中的json调用方法
    本文介绍了在express工程中如何调用json数据,包括建立app.js文件、创建数据接口以及获取全部数据和typeid为1的数据的方法。 ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
  • 本文介绍了常用的编辑器快捷键,包括快速转换编辑器、浏览选项卡、提取本地变量和方法、编辑器窗口最大化等功能。通过使用这些快捷键,可以提高编辑器的使用效率,减少复杂度,并提升代码的可测试性。 ... [详细]
  • 【具体报错信息】ErrorparsingD:\android-sdks\system-images\android-22\android-wear\armeabi-v7a\devi ... [详细]
  • Allegro总结:1.防焊层(SolderMask):又称绿油层,PCB非布线层,用于制成丝网印板,将不需要焊接的地方涂上防焊剂.在防焊层上预留的焊盘大小要比实际的焊盘大一些,其差值一般 ... [详细]
author-avatar
mobiledu2502877427
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有