Categories
未分类

AndroidStudio调试小技巧

我在这一行代码打了个断点: 我能不能让代码走到这里的时候,IDE不停下来,而是打个log出来,告诉我代码走到这里了呢? 你可能会问,为什么,你为什么会有那样的需求? 因为我只是想知道代码有没有走到这里,并不是想让它停下来。 你可能又要问,你在那个地方加一行log,重新运行不就好了吗? 这样做确实可以,但是如果你的项目特别大,运行一次需要几分钟甚至十几分钟的时候,你就会尽量避免修改代码重新运行。 这时候,如果你手机上已经装了这个app,你就会想要通过断点的方式,来判读代码会不会走到某个地方。 这就回到我们开头的问题了,能不能让代码走到那个断点的时候,不停下来,而是打个log出来,告诉我代码走到那里了呢? 我探索了一下,发现确实可以! 在调试面板点击这个图标: 会出来下面这个界面: 左边选中相应的断点,勾掉“Suspend”,勾上“Breakpoint hit” message,如下图所示: 再次进行相应的用户操作,触发断点的代码,在调试面板的“Console” Tab,你就会看到断点打出来的log,表示这行代码被触发了。如下图所示。 在这里,你甚至可以自定义打印的log内容,勾上“Evaluate and log”,输入你想要打印的表达式,如下图所示: 效果如下:

Categories
未分类

安卓单元测试(八):Junit Rule的使用

JUnit Rule是什么 一个JUnit Rule就是一个实现了TestRule的类,这些类的作用类似于@Before、@After,是用来在每个测试方法的执行前后执行一些代码的一个方法。 如果你不清楚@Before、@After这些Annotation的意思,Chances are你还不了解Junit的使用,建议先看这篇文章。 那为什么不直接用这些annotation呢?这是因为它们都只能作用于一个类,如果同一个setup需要在两个类里面同时使用,那么你就要在两个测试类里面定义相同的@Before方法,然后里面写相同的代码,这就造成了代码重复。有的人说你可以用继承啊,首先我想说,我很讨厌继承这个东西,所以如果可以不用继承的话,我就不会用;再次我想说,如果你不讨厌继承的话,从现在开始,你也应该慢慢的讨厌它了。 此外,JUnit Rule还能做一些@Before这些Annotation做不到的事情,那就是他们可以动态的获取将要运行的测试类、测试方法的信息。这个在接下来的一个例子里面可以看到。 怎么用JUnit Rule? 使用框架自带的Rule 很多测试框架比如JUnit、Mockito自带给我们很多已经实现过好了的JUnit Rule,我们可以直接拿来用。比如Timeout,TemporaryFolder,等等。这些Rule的使用方法非常简单。定义一个这些类的public field,然后用@Rule修饰一下就好了。比如 public class ExampleTest { @Rule public Timeout timeout = new Timeout(1000); //使用Timeout这个 Rule, @Test public void testMethod1() throws Exception { //your tests } @Test public void testMethod2() throws Exception { //your tests2 } //other test methods } 那么,对于上面这个ExampleTest的每一个测试方法。它们的运行时间都不能超过1秒钟,不然就会标志为失败。而它的实现方式就是在每个方法测试之前都会记录一下时间戳,然后开始倒计时,1秒钟之后如果方法还没有运行结束,就把结果标记为失败。 这里需要注意的一点是Rule需要是public field […]

Categories
未分类

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

大家好,我是蘑菇街支付金融部门的邹勇,花名叫小创。今天很高兴跟大家分享一下安卓的单元测试在蘑菇街支付金融的实践。下面,我们从为什么开始。 为什么要写单元测试 首先要介绍为什么蘑菇街支付金融这边会采用单元测试的实践。说起来比较巧,刚开始的时候,只是我一个人会写单元测试。后来老板们知道了,觉得这是件很有价值的事情,于是就叫我负责我们组的单元测试这件事情。就这样慢慢的,单元测试这件事情就成了我们这边的正常实践了。再后来,在公司层面也开始有一定的推广。 要说为什么要写单元测试的话,我相信大部分人都能承认、也能理解单元测试在保证代码质量,防止bug或尽早发现bug这方面的作用,这可能是大家觉得单元测试最大的作用。然而我觉得,除了这方面的作用,单元测试还能在很大程度上改善代码的设计,同时还能节约时间,让人工作起来更自信、更开心,以及其他的一些好处。这些都是我的切身感受,我相信也是多数真正实践过单元测试的人的切身感受,而不是为了宣传这个东西而说的好听的大话。 说到节约时间,大家可能就会好奇了,写单元测试需要时间,维护单元测试代码也需要时间,应该更费时间才对啊? 这就是在开始分享之前,我想重点澄清的一点,那就是,单元测试本身其实不会占用多少时间,相反,还会节约时间。只是:1. 学习如何做单元测试需要时间;2. 在一个没有单元测试的项目中加入单元测试,需要一定的结构调整的时间,因为一个有单元测试跟没有单元测试的项目,结构上还是有较大不同的。 打个比方,开车这件事情,需要很多时间吗?我相信很少人会说开车这件事情需要很多时间,而是:1. 学习开车,需要一定的时间;2. 如果路面不平的话,那么修路需要一定的时间。单元测试也是类似的情况。 那为什么说单元测试可以节约时间呢?简单说几点:1. 如果没有单元测试的话,就只能把app运行起来测试,这比运行一次单元测试要慢多了。2. 尽早发现bug,减少了debug和fixbug的时间。3. 重构的时候,大大减少手动验证重构正确性的时间。 所以,我希望大家能去掉”没时间写单元测试”这个印象,如果工作上安排太紧,没有时间学习如何做单元测试的话,可以自己私底下学,然后在慢慢应用到项目中。 单元测试简单介绍,以及void方法怎么测 接下来介绍我们这边是怎么做安卓单元测试的。首先澄清一下概念,在安卓上面写测试,有很多技术方案。有JUnit、Instrumentation test、Espresso、UiAutomator等等,还有第三方的Appium、Robotium、Calabash等等。我们现在讲的是使用JUnit和其他的一些框架,写可以在我们开发环境的JVM上面直接运行的单元测试,其他的几种其实都不属于单元测试,而是集成测试或者叫Functional test等等。这两者明显的不同是,前者可以直接在开发用的电脑,或者是CI上面的JVM上运行,而且可以只运行那么一小部分代码,速度非常快。而后者必须要有模拟器或真机,把整个project打包成一个app,然后上传到模拟器或真机上,再运行相关的代码,速度相对来说慢很多。 单元测试的定义相信大家都知道,就是为我们写的某一个代码单元(比如一个方法)写的测试代码。一个单元测试大概可以分为三个部分: setup:即new 出待测试的类,设置一些前提条件 执行动作:即调用被测类的被测方法,并获取返回结果 验证结果:验证获取的结果跟预期的结果是一样的 然而一个类的方法分两种,一种是有返回值的方法。一种是没有返回值的方法,即void方法。对于有返回值的方法,固然测试起来是很容易的,但是对于没有返回值的方法,该怎么测试呢?这里的关键是,怎么样获取这个方法的“返回结果”? 这里举一个例子来说明一下,顺便澄清一个十分常见的误解。比如说有一个Activity,管他叫DataActivity,它有一个public void loadData()方法, 会去调用底层的DataModel类,异步的执行一些网络请求。当网络请求返回以后,更新用户界面。 这里的loadData()方法是void的,它该怎么测试呢?一个最直接的反应可能是,调用loadData()方法(当然,实际可能是通过其他事件触发),然后一段时间后,验证界面得到了更新。然而这种方法是错的,这种测试叫集成测试,而不是单元测试。因为它涉及到很多个方面,它涉及到DataModel、网络服务器,以及网络返回正确时,DataActivity内部的处理,等等。集成测试固然有它的必要性,但不是我们应该最关注的地方,也不是最有价值的地方。我们应该最关注的是单元测试。关于这一点,有一个Test Pyramid的理论: Test Pyramid理论基本大意是,单元测试是基础,是我们应该花绝大多数时间去写的部分,而集成测试等应该是冰山上面能看见的那一小部分。 那么对于这个case,正确的单元测试方法,应该是去验证loadData()方法调用了DataModel的某个请求数据的方法,同时传递的参数是正确的。“调用了DataModel的方法,同时参数是。。。” 这个才是loadData()这个方法的“返回结果”。 Mock的概念以及Mockito框架 要验证某个对象的某个方法得到调用了,就涉及到mock的使用。这里对mock的概念做个简单介绍,以免很多同学不熟悉,mock就是创建一个虚假的、模拟的对象。在测试环境下,用来替换掉真实的对象。这样就能达到两个目的:1. 可以随时指定mock对象的某个方法返回什么样的值,或执行什么样的动作。 2. 可以验证mock对象的某个方法有没有得到调用,或者是调用了多少次,参数是什么等等。 要使用mock,一般需要使用mock框架,目前安卓最常用的有两个,Mockito和JMockit。两者的区别是,前者不能mock static method和final class、final method,后者可以。我们依然采用的是Mockito,原因说起来惭愧,是因为刚开始并不知道JMockit这个东西,后来查了一些资料,看过很多对比Mockito和JMockit的文章,貌似大部分还是很看好JMockit的,只是有一个问题,那就是跟robolectric的结合也有一些bug,同时使用姿势跟Mockito有较大的不同,因此一直没有抽时间去实践过。这个希望以后能够做进一步的调查,到时候在给大家分享一下使用感受。 但是使用Mockito,就有一个问题,那就是static method和final class、final method没有办法mock,对于这点如何解决,我们稍后会介绍到。 在测试环境中使用mock:依赖注入 接下来的一个问题就是,如何在测试环境下,把DataModel换成mock的对象,而正式代码中,DataModel又是正常的对象呢? 这个问题也有两种解决方案,一是使用专门的testing product flavor;二是使用依赖注入。第一种方案就是用一个专门的product […]

Categories
未分类

Android单元测试(三):JUnit单元测试框架的使用

我们写单元测试,一般都会用到一个或多个单元测试框架,在这里,我们介绍一下 JUnit4 这个测试框架。这是 Java 界用的最广泛,也是最基础的一个框架,其他的很多框架,包括我们后面会看到的 Robolectric,都是基于或兼容 JUnit4 的。 然而首先要解决的问题是。。。 为什么要使用单元测试框架 或者换句话说,单元测试框架能够为我们做什么呢? 从最基本的开始说起,假如我们有这样一个类: public class Calculator { public int add(int one, int another) { // 为了简单起见,暂不考虑溢出等情况。 return one + another; } public int multiply(int one, int another) { // 为了简单起见,暂不考虑溢出等情况。 return one * another; } } 如果不用单元测试框架的话,我们要怎么写测试代码呢?我们恐怕得写出下面这样的代码: public class CalculatorTest { public static void main(String[] args) […]

Categories
未分类

Java 8的Lambda及其在Android 开发中的应用

上次在盆友圈发了一张照片 上面的两段代码是完全等效的,但是代码行数从11行降低到了一行,更不用说在第一段代码里面,我在run方法的前后以及内部都没有加入任何的空行。由此可以看出,使用lambda可以让你的Java代码在某些情况下达到何等的简洁。 那么问题来了。。。 什么叫lambda呢? Java 8 给我们带来了lambda,然而在Oracle的文档中,我没有找到lambda的定义,wikipedia里面也没有找到适合Java中的lambda的定义。写这篇文章的时候,我在这里 看到一篇很好的介绍lambda的文章,它里面给了一个定义,我觉得还挺合适的。 A lambda expression is a block of code with parameters. lambda的写法 首先列举一个完整的lambda expression: (int a, int b) -> { System.out.println(“Performing add operation…”); return a+b; } 一个lambda expression由三部分组成: – 参数:(int a, int b)是这个lambda expression的参数部分,包括参数类型和参数名 – 箭头:-> – 代码块:就是用”{}”包含着的那两句代码。 上面说的是一个完整的lambda表达式,在很多情况下,很多东西是可以省略的。比如说,当系统可以根据context自动推断出参数的类型的时候,参数类型是可以神略的。这样的话就可以写成: (a, b) -> { System.out.println(“Performing add operation…”); return a+b; […]