Android单元测试在蘑菇街支付金融部门的实践

发表于:2016-8-26 11:57

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:邹小创    来源:51Testing软件测试网采编

分享:
  遇到的坑,以及好的practice建议
  接下来讲讲我们遇到的一些坑,以及一些好的practice建议。
  1. Native libary
  无论是纯JUnit还是Robolectric,都不支持load native library,会报UnsatisfiedLinkError的错。所以如果你的被测代码里面用到了native lib,那么可能需要给System.loadLibrary加上try catch。
  如果是被测代码用到的第三方lib,而里面用到了native lib的话,一般有两种解决办法,一种是将用到native lib的第三方类外面自己在包一层,然后在测试的情况下mock掉。第二种是用Robolectric,给那个类创建一个shadow class。
  第一种方法的好处是可以在测试的时候随时改变这个类的返回值或行为,缺点是需要另外创建一个wrapper类,会有点繁琐。第二种方式不能随时改变这个类的行为,但是写起来非常简单。所以,看自己的需要,选择相应的方法。
  这两种方法,也是解决static method, final class/method不能mock的主要方式。
  2. 尽量写出易于测试的代码
  static method、直接new object、singleton、Global state等等这些都是一些不利于测试的代码方式,应该尽量避免,用依赖注入来代替这些方式。
  3. 不要重复你的unit test
  比如说你使用了一个builder模式来创建了一个类,这个builder有一个validator,来validate一些参数情况。那么这种情况,builder跟validator分开测,用各种正确的错误的参数情况去测试validator,然后测builder的时候,就不用遍历各种有效的跟无效的参数去测试了。
  因为如果这样的话,到时候Validator的逻辑改了,那么针对Validator的测试跟针对Builder的测试都要修改,这个其实是重复的。这里只需要测试这个builder里面有一个Validator就好了。
  4. 公共的单元测试library
  如果你们公司也是组件化开发的话,抽出一个公共的单元测试类库来做单元测试,里面可以放一些公共的helper、utils、rules等等,这个可以极大的提高写单元测试的速度。
  5. 把安卓里面的“纯java”代码copy一份到自己的项目里面
  安卓里面有些类其实跟安卓没太大关系的,比如说TextUtils、Color等等,这些类完全可以把代码copy出来,放到自己的项目里面,然后其他地方就用这个类,这样也能部分摆脱android的依赖,使用JUnit而不是Robolectric,提高运行test的速度。
  6. 充分发挥JUnit Rule的作用
  JUnit Rule是个很强大的工具,然而知道的人却不多。它的基本作用是,让你在执行某个测试方法前后,可以做一些事情。如果你的好几个测试类里面有很多的共同的setup、teardown工作,你可能会倾向于使用继承,结合@Before、@After来减少duplication,这里更建议大家使用JUnit Rule来实现这个目的,而不是用继承,这样可以有更大的灵活性。
  比如,为了方便测试Activity的method,我们有一个ActivityRule,在跑一个测试方法之会启动target Activity,然后跑完以后自动finish这个activity。
  其中一个比较有趣的用JUnit Rule实现的功能,是实现类似于BDD测试框架的命名方式。做单元测试的时候,你经常需要为同一个方法写好几个测试方法,每个测试方法测试不同的点。为了让命名更具可读性,我们往往会把名字写的很长,在这种情况下,如果用驼峰命名的话,需要不断切换大小写,写起来麻烦,可读性也不高。如果用下划线的话,写起来也很麻烦。如果你使用过BDD的一些框架(比如RSpec、Cucumber、Jasmine等),你就会异常怀念那种“命名”方式。如果你没用过的话,那种“命名”方式大概是这样的:
  describe Hash do
  # 一下是一个测试方法,it后面的字符串就是这个测试方法的“命名”
  it "hashes the correct information in a key" do
  expect(hash[:hello]).to eq('world')
  end
  end
  这里的关键是,当测试方法失败的时候,这个字符串是要能被加到错误信息里面的。我们做了个JUnit Rule来达到这个效果。做法是结合一个自定义的annotation,这个annotation接收一个String,来描述这个测试方法的测试目的。在Rule里面将这个annotation读出来,如果测试没通过的话,把这个描述性的String加到输出的error message里面。这样在批量运行的时候,一看就知道没通过的测试是测什么东西的。而测试方法的命名则可以比较随意。
  达到的效果如下:
  如果运行失败,得到如下的结果
  关于JUnit Rule的使用,大家可以自行google一下,也不难。
  7. 善于利用AndroidStudio来加快你写测试的速度
  AndroidStudio有很多feature可以帮助我们更快的写代码,比如code generation和live template。这点对于写正式代码也适用,不过对于写测试代码来说,效果更为突出。因为大部分测试代码的结构、风格都是类似的,在这里live template能起非常大的作用。此外,如果你先写测试,可以直接写一些还不存在的Class或method,然后alt+enter让AndroidStudio自动帮你生成。
  8. 不要最求完美
  刚开始的时候,不用追求测试代码的质量,也不用追求完美,如果有些地方不好写测试,可以先放放,以后再来补,有部分测试总比没有测试好。Martin Fowler说过
  Imperfect tests, run frequently, are much better than perfect tests that are never written at all.
  然而等你熟悉写测试的方法以后,强烈建议先写测试!因为如果你先写了正式代码,那你对这写代码是如何work的已经有一个印象了,因此你往往会写出能顺利通过的测试,而忽略一些会让测试不通过的情况。如果先写测试,则能考虑得更全面。
  9. 未来的打算
  使用Groovy和RoboSpock或者是Kotlin和Spek,真正实现BDD,这是很可能的事情,只是目前我们这边还没太多那方面的实践,因此就不说太多了。以后有一定实践了,到时候可以再更大家交流。
22/2<12
精选软件测试好文,快来阅读吧~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号