是当前最流行的 单元测试 框架。采用 框架,我们可以 虚拟 出一个 外部依赖,降低测试 组件 之间的 耦合度,只注重代码的 流程与结果,真正地实现测试目的。
的中文译为仿制的,模拟的,虚假的。对于测试框架来说,即构造出一个模拟/虚假的对象,使我们的测试能顺利进行下去。
测试就是在测试过程中,对于某些 不容易构造(如 必须在 容器中才能构造出来)或者不容易获取 比较复杂 的对象(如 中的 对象),用一个 虚拟 的对象( 对象)来创建,以便测试方法。
单元测试 是为了验证我们的代码运行正确性,我们注重的是代码的流程以及结果的正确与否。
对比真实运行代码,可能其中有一些 外部依赖 的构建步骤相对麻烦,如果我们还是按照真实代码的构建规则构造出外部依赖,会大大增加单元测试的工作,代码也会参杂太多非测试部分的内容,测试用例显得复杂难懂。
采用 框架,我们可以 虚拟 出一个 外部依赖,只注重代码的 流程与结果,真正地实现测试目的。
- 可以很简单的虚拟出一个复杂对象(比如虚拟出一个接口的实现类);
- 可以配置 对象的行为;
- 可以使测试用例只注重测试流程与结果;
- 减少外部类、系统和依赖给单元测试带来的耦合。
如图所示,使用 的大致流程如下:
- 创建 外部依赖 的 对象, 然后将此 对象注入到 测试类 中;
- 执行 测试代码;
- 校验 测试代码 是否执行正确。
在 的 中添加如下内容:
这里稍微解释下:
- : 用于 本地单元测试,其测试代码路径位于
- : 用于 设备测试,即需要运行 设备进行测试,其测试代码路径位于
mockito-core最新版本可以在 Maven 中查询:mockito-core。 mockito-android最新版本可以在 Maven 中查询:mockito-android
普通单元测试使用 ,路径:
这里摘用官网的 :
这里 了一个 (这里只是为了用作 示例,通常对于 这种简单的类对象创建而言,直接 一个真实的对象即可,无需进行 ), 会检验对象是否在前面已经执行了相关行为,这里 在 之前已经执行了 和 行为,所以 会通过。
这里对几个比较重要的点进行解析:
when(mockedList.get(0)).thenReturn("first")
这句话 会解析为:当对象 调用 方法,并且参数为 时,返回结果为,这相当于定制了我们 对象的行为结果( 对象为 ,指定其行为 ,则返回结果为 )。
mockedList.get(999)
由于 没有指定 的行为,所以其结果为 。因为 的底层原理是使用 动态生成一个 代理类对象,因此, 出来的对象其实质就是一个 代理,该代理在 没有配置/指定行为 的情况下,默认返回 空值。
上面的 使用的是 静态方法 模拟出一个实例,我们还可以通过注解 也模拟出一个实例:
对于标记有 , , 等注解的成员变量的 初始化 到目前为止有 种方法:
- 对 测试类添加
- 在标示有 方法内调用初始化方法:
上面的测试用例,对于 等注解的成员变量的初始化又多了一种方式 。规则 会自动帮我们调用 去 实例化 出 注解 的成员变量,我们就无需手动进行初始化了。
- 对于所有方法, 对象默认返回 ,原始类型/原始类型包装类 默认值,或者 空集合。比如对于 类型,则返回 ,对于 则返回 。
- 行为配置()是可以被复写的:比如通常的对象行为是具有一定的配置,但是测试方法可以复写这个行为。请谨记行为复写可能表明潜在的行为太多了。
- 一旦配置了行为,方法总是会返回 配置值,无论该方法被调用了多少次。
- 最后一次行为配置是更加重要的,当你为一个带有相同参数的相同方法配置了很多次,最后一次起作用。
通过参数对象的 方法来验证参数是否一致,当需要更多的灵活性时,可以使用参数匹配器:
参数匹配器 允许更加灵活的 验证 和 行为配置。更多 内置匹配器 和 自定义参数匹配器 例子请参考:,
注意:如果使用了参数匹配器,那么所有的参数都需要提供一个参数匹配器。
类似 , 这类匹配器并不返回匹配数值。他们内部记录一个 匹配器堆栈 并返回一个空值(通常为 )。这个实现是为了匹配 编译器的 静态类型安全,这样做的后果就是你不能在 检验/配置方法 外使用 , 等方法。
校验次数方法常用的有如下几个:
|Method |Meaning| |:------|:-------| |times(n)| 次数为n,默认为1(times(1))| |never()| 次数为0,相当于times(0)| |atLeast(n)|最少n次| |atLeastOnce()| 最少一次| |atMost(n)| 最多n次 |
有时对于一些行为,有先后顺序之分,所以,当我们在校验时,就需要考虑这个行为的先后顺序:
对于同一个方法,如果我们想让其在 多次调用 中分别 返回不同 的数值,那么就可以使用存根连续调用:
也可以使用下面更简洁的存根连续调用方法:
注意:存根连续调用要求必须使用链式调用,如果使用的是同个方法的多个存根配置,那么只有最后一个起作用(覆盖前面的存根配置)。
对于 返回类型 为 的方法,存根要求使用另一种形式的 函数,因为编译器要求括号内不能存在 方法。
例如,存根一个返回类型为 的方法,要求调用时抛出一个异常:
前面使用的都是 出来一个对象。这样,当 没有配置/存根 其具体行为的话,结果就会返回 空类型。而如果使用 特务对象(),那么对于 没有存根 的行为,它会调用 原来对象 的方法。可以把 想象成局部 。
注意:由于 spy 是局部 mock,所以有时候使用 when(Object) 时,无法做到存根作用。此时,就可以考虑使用 doReturn() | Answer() | Throw() 这类方法进行存根:
并不是 真实对象 的 代理。相反的,它对传递过来的 真实对象 进行 克隆。所以,对 真实对象 的任何操作, 对象并不会感知到。同理,对 对象的任何操作,也不会影响到 真实对象。
当然,如果使用 进行对象的 局部 ,通过 方法也是可以的:
以 行为驱动开发 的格式使用 //given //when //then 注释为测试用法基石编写测试用例,这正是 官方编写测试用例方法,强烈建议使用这种方式测试编写。
构造器,方法,成员变量依赖注入 使用 注解时, 会检查 类构造器,方法或 成员变量,依据它们的 类型 进行自动 。
成员变量 类型为 ,它的上面标识别了 。这意味着要 出 , 需要先自动 出 所需的 构造参数(即: 和 ),最终 得到一个 ,赋值给 。
允许在 的时候获取 方法参数内容,这使得我们能在 测试过程 中能对 调用方法参数 进行 捕捉 并 测试。
- 不能 静态方法;
- 不能 构造器;
- 不能 和 方法。
最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走
这些资料,对于从事【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….有需要的小伙伴可以点击下方小卡片免费领取
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/4972.html