当前位置: 首页 > 工具软件 > jMock > 使用案例 >

java多态软件测试工具,JMock测试框架—自动化测试主流工具(4)

贺君浩
2023-12-01

3.4 JMock测试框架

JMock是用于创建Mock对象的工具框架,它基于Java开发,在Java测试与开发环境中有不可比拟的优势。更重要的是,JMock大大简化了虚拟对象的使用。

3.4.1 驱动和桩

3.3节讲到了驱动和桩,那么究竟什么是驱动呢?这个很好理解,测试夹具就是驱动。那么什么是桩呢?桩有何价值呢?

举一个简单的例子,一个简单的程序有3个函数,即A、B、C,函数的调用关系为A→B→C,那么现在要测试函数C,只需要写一个驱动去调用C即可。那么如果要测试B呢?驱动肯定要有。另外,为了使B测试时不受C的影响,需要隔离C,那么怎么隔离呢?用桩C#代替C,让B调用C#而不是C。而C#桩是可以由测试人员来控制的,想让它返回什么结果就返回什么结果,这样就可以达到隔离的效果。

再考虑另外一种场景,现在要对B函数进行测试,但是C函数还没有实现。毫无疑问,若B函数是无法运行的,测试必然无法正常进行。那么怎么办?写一个桩——C##,伪装成C好像已经实现,这样B就可以成功运行,从而达到测试目的。

例如,StringHandle类中的isNumber方法还没有实现,那么可以采用这种方法来实现isNumber,代码如图3-36所示。

public boolean isNumber(String source) {

return true;

}

图3-36 关于isNumber的示例

以上代码完全可以让调用isNumber的代码运行起来,不过这里有一个比较严重的问题:将开发的代码更改了,强行在StringHandle类中加入了一个“伪装”的isNumber方法。这显然会有问题,测试人员不能通过修改开发的原始代码来达到测试目的。另外,通常被测代码不一定是源代码,有可能是打包好的JAR包,调用JAR包中的接口来进行测试,这个时候是没有办法改变代码的,那么究竟如何处理,才能从根本上解决这一问题呢?答案是使用Mock对象。

3.4.2 Mock对象

顾名思义,Mock对象用来假冒一个方法,达到隔离环境的目的,适用于对一些还没有实现的方法的模拟。其实,只要真正理解了“多态”的使用,使用Mock对象就不会有任何问题,所以Mock的核心在于“多态”。下面基于多态特性来介绍Mock对象。

要使用Mock,必须借助多态性。同样,要使用多态性,必须借助接口。显然,之前并没有使用任何接口来定义规范,而直接使用类方法来完成。所以,需要对StringHandle类进行适当改造,让它可以实现多态性。为了对比改造后与改造前的区别,建议新建一个包,专门存放改造后的代码,在此创建一个新的包com.learn.updated,将com.learn.compare目录下的所有源代码复制过来。

首先,定义IString接口,定义方法isNumber,代码如图3-37所示。

package com.learn.updated;

public interface IString {

public boolean isNumber(String source);

}

图3-37 定义接口和方法

然后,把StringHandle类改造成实现IString接口的实现类,代码如图3-38所示。

package com.learn.updated;

import Java.io.BufferedReader;

import Java.io.IOException;

import Java.io.InputStreamReader;

图3-38 改造类

import Java.util.Arrays;

import Java.util.Vector;

public class StringHandle {

public IString istring;    // 定义接口变量istring

// 从控制台输入字符串

public Integer[] inputString() {

// 代码不变,此处省略

}

// 将字符串解析成数组

public Integer[] splitString(String source, String delimiter) {

Vector vector = new Vector();

int position = source.indexOf(delimiter);

while (source.contains(delimiter)) {

String value = source.substring(0, position);

if (istring.isNumber(value)) {    // 将该行修改成istring.isNumber

vector.add(Integer.parseInt(value));

}

else {

Integer[] result = {1};

return result;

}

source = source.substring(position + 1, source.length());

position = source.indexOf(delimiter);

}

vector.add(Integer.parseInt(source));

Integer[] array = new Integer[vector.size()];

vector.copyInto(array);

return array;

}

// 检查字符串是否可正常转换为数字

public boolean isNumber(String source) {

// 删除该方法

}

}

图3-38 改造类(续)

以上代码的核心在于使用istring来调用其方法isNumber,而不是直接通过this.isNumber调用,这样就可以通过将不同的实例传递给istring来实现Mock的方法。

接下来,创建一个新的包com.learn.jmock,并创建一个Mock类MockIString.Java,代码如图3-39所示。

package com.learn.jmock;

import com.learn.updated.*;

public class MockIString implements IString {

图3-39 创建包和类

public boolean isNumber(String source) {

return true;

}

}

图3-39 创建包和类(续)

最后,使用Mock对象来对StringHandle.splitString进行测试,具体代码(StringHandle- Mock.Java)如图3-40所示。

package com.learn.jmock;

import static org.junit.Assert.assertArrayEquals;

import org.junit.Test;

import com.learn.updated.StringHandle;

public class StringHandleMock {

@Test

public void splitString() {

StringHandle stringHandle = new StringHandle();

stringHandle.istring = new MockIString();

String source = "333,111,222,666";

Integer[] expect = {333, 111, 222, 666};

Integer[] actual = stringHandle.splitString(source, ",");

assertArrayEquals(expect, actual);

}

}

图3-40 进行测试的具体代码

上述代码通过了测试,虽然看到StringHandle中并没有实现isNumber,但是由于在MockIString中实现了它,利用多态性将MockIString的实例传递给StringHandle类的istring接口变量,这样splitString方法就可以正常使用istring.isNumber了。这样做并不会修改到被测试的源代码,从根本上解决了使用桩所遇到的各种问题。

Mock对象的使用范畴如下。

●真实对象具有不可确定的行为,产生不可预测的效果(如股票行情、天气预报)。

●真实对象很难创建。

●真实对象的某些行为很难触发。

●真实对象实际上还不存在(和其他开发小组或者新的硬件交互)等。

使用Mock对象测试的关键步骤如下。

(1)使用一个接口来描述这个对象。

(2)在产品代码中实现这个接口。

(3)在测试代码中实现这个接口。

在被测代码中只通过接口来引用对象,所以代码不知道引用的对象是真实对象还是Mock对象。

版权声明:51Testing软件测试网获得人民邮电出版社和作者授权连载本书部分章节。

任何个人或单位未获得明确的书面许可,不得对本文内容复制、转载或进行镜像,否则将追究法律责任。

 类似资料: