如何使用JUnit进行自动化测试
1 如何利用JUnit在 Eclipse中开发自动化脚本
JUnit可以和很多开发工具进行集成来进行单元测试,我们这里选取较常用的java开发工具Eclipse来使用JUnit4进行单元测试。如何在开发工具Eclipse里进行单元测试
首先新建一个项目叫JUnit_Test,我们编写一个Calculator类,这是一个能够简单实现加减乘除、平方、开方的计算器类,然后对这些功能进行单元测试。这个类并不是很完美,我们故意保留了一些Bug用于演示,这些Bug在注释中都有说明。该类代码如下:
package andycpp;
public class Calculator
{
private static int result; etEngineByName( \"JavaScript\" );
if ( null != text )
{
try
{
Object value = ( text );
if ( value != null )
{
return ( value );
}
} catch ( ScriptException e )
{
();
}
}
return \"failed\";
}
}
我们先看一下CalculateService的单元测试如何写?
第一步要测试这个类,那我们首先要创建一个这样的对象
代码如下:
@Before
public void setUp()
{
CalculateService service= new CalculateService();
}
使用Before标签还是 BeforeClass的决定条件在于,你要测试的方法是不是每次都要重新创建一个service
第二步明确要测试的方法,并根据要测试的方法,分析测试所需要覆盖的场景。
1. 我们要测的方法为calculate;
2. 该方法需要覆盖的场景为:
1)输入参数text为null
2)过程中value是null(这种情况的话,输入参数为”null”)
3) 运算中出现异常
4) 运算正常输出结果
那我们针对这几个场景,写测试代码如下:
@Test
public void should_return_failed_when_input_is_null()
{
assertEquals( \"failed\
}
@Test
public void should_return_failed_when_input_is_string_null()
{
assertEquals( \"failed\
}
@Test
public void should_return_failed_when_input_is_not_can_calculate()
{
assertEquals( \"failed\
}
@Test
public void should_return_5_when_input_is_1_and_4()
{
assertEquals( \"\
}
通过调用service类的 calculate方法,并给予不同的输入参数以创建不同的场景,从而验证当前方法是否正确。
上面就是CalculateService的单元测试,那我们下面看下CalculateModel类,并一起来写一下他的单元测试要如何去写
CalculateModel类的代码如下:
package model;
import ;
public class CalculateModel implements ICalculateModel
{
private ICalculateService service;
public CalculateModel( ICalculateService service )
{
= service;
}
@Override
public String calculate( String text )
{
return ( text );
}
}
我们可以按照上面的步骤去写测试类
第一步创建要测试的对象,这里由于CalculateModel的创建依赖于CalculateService,所以我们要先创建CalculateService;
代码如下:
@Before
public void setUp()
{
CalculateService service= new CalculateService ();
CalculateModel model = new CalculateModel (service );
}
第二步明确要测试的方法,并根据要测试的方法,分析测试所需要覆盖的场景。
1. 我们要测的方法为calculate;
2、根据代码我们可以看出该方法需要覆盖的场景只有一个,就是不论输入的参数如何,也不管运算的结果是什么,只要调用了CalculateService的calculate方法,并把结果返回出去即可。
测试代码如下:
@Test
public void should_return_2_when_input_is_1_multiply_2 ()
{
String text = \"1*2\";
assertEquals( \"2\
}
粗略一看好像没什么问题,但是我们仔细想一下,如果CalculateService的calculate方法出错的话,那么这个测试用例就会报错,因为返回结果就会发生错误。也就是说我们现在在测CalculateModel,但我们同时还要保证CalculateService的正确,这样显然是有问题的,因为CalculateService不是我们这次测试的对象,它在别的测试类中已经覆盖过了。那么如何解决这个问题呢?
3.1 结合EasyMock的单元测试写法
下面我们用EasyMock来写这个测试用例。
首先,因为我们对CalculateService不关心,所以我们用EasyMock来Mock一个CalculateService。
@Before
public void setUp()
{
CalculateService service= createMock( );
CalculateModel model = new CalculateModel( service );
}
然后我们重新用EasyMock的方式来编写这个测试方法,
由于CalculateService 是被 mock出来的,而非真正的创建这么一个对象,所以对象的方法不会真的运行,所以需要期待调用一下,同时这个方法拥有一个返回值,所以需要我们给它指定一个我们希望的返回值。(如果后面的方法需要依赖这个返回值作为判断执行的条件,如”if(a==0){}” 那么我们这个返回值 “a” 就需要根据我们希望测试的场景来给指定)
然后我们需要replay一下这个mock对象,以激活它,
最后再在程序的结尾verify一下,来验证它的调用是否和我们期待的一致。
@Test
public void should_return_2_when_input_is_1_multiply_2()
{
String text = \"1*2\";
expect( ( text ) ).andReturn( \"2\" );
replay( service );
assertEquals( \"2\
verify( service );
}
总结一下,EasyMock进行单元测试的过程大致可以划分为以下几个步骤:
1、使用 EasyMock 生成 Mock 对象;
2、设定 Mock 对象的预期行为和输出;
3、将 Mock 对象切换到 Replay 状态;
4、调用 Mock 对象方法进行单元测试;
5、对 Mock 对象的行为进行验证。
3.2 元素
这里我们仅介绍我们在自动化测试中会用到的元素,对于其它元素大家可以参考EasyMock
官网
createMock
这个方法的作用是Mock一个我们不希望实际创建的对象。
这个方法有好几个重载方法,我们最常用的是一个参数的,这个参数为我们要Mock对像的类型如:ICalculateService service= createMock( );
expect
这个方法是期待调用Mock对象带返回值的方法。它的后面通常需要and…方法来指明它执行的结果。
expectLastCall
Mock对象没有返回值的方法,只需要在测试中直接录制这个方法即可,不需要用expect去期待它执行。但有的时候,我们可能会期望它会有一个异常抛出,或着指定它要执行多少次这个时候,我们就需要用到expectLastCall方法,这个方法的用法如下:
();
expectLastCall().andThrow( new Exception( \"异常\" ) );
表明在执行Mock对象service的noReturnMethod方法时,期望它向外抛出一个异常。
andReturn
期望该方法的返回值,参数为 Object
andThrow
期望该方法抛出一个异常,参数为 Throwable
andAnswer
期望该方法返回一个值或抛出一个异常,这个过程可以通过一段程序来进行。如:
expect( “2” ) ).andAnswer( new IAnswer< String >()
{
@Override
public String answer() throws Throwable
{
return 2*5*3;
}
});
andDelegateTo
用法和andAnswer()方法类似,但需要建立一个类,这个类要实现Mock对象的接口,用法如下:
publicclassServiceStubimplementsService{
publicintexecute(intcount){
returncount*2;
}
}
@Test
publicvoidtestRuntimeReturn(){
Businessbusiness=newBusiness();
Serviceservice=;
(service);
())).andDelegateTo(newServiceStub());
(service);
();
(service);
}
any
这里面包括 anyBean(),anyByte(),anyChar(),anyInt(),anyLong(),anyFloat(),anyDouble(),anyShort(),
anyObject(),anyString();
用法:当期待执行的mock方法参数值不确定时,可以根据参数的类型来模拟。如:
expect( ( anyString() ) ).andReturn( \"2\" );
times
用来指定某一方法执行的次数,如果次数不确定那么可以用anyTimes方法。
expect( (\"1*2\" ) ).andReturn( \"2\" ).times(2); 表明期望该方法执行两次
expect( (\"1*2\") ).andReturn( \"2\" ). anyTimes();表明期望该方法执行若干次。
isA
用法:当期待执行的mock方法参数值为一个对象,并且不确定具体对象时,可以根据参数的类型来模拟。如:
expect( ( isA ) ).andReturn( \"2\" );
isNull
用法:当期待执行的mock方法参数值为null时,用该方法来声明。
expect( ( isNull()) ).andReturn( \"2\" );
notNull
用法:当期待执行的mock方法参数值不为null时,用该方法来声明。
expect( ( notNull()) ).andReturn( \"2\" );
startWith
用来模糊表达一个值 ,指明这个值以某个字符串开始。
expect( ( startWith(\"1\")) ).andReturn(\"2\");
endWith
用来模糊表达一个值 ,指明这个值以某个字符串开始
expect( ( endWith(\"2\")) ).andReturn(\"2\");
matches
用来模糊表达一个值 ,指明这个值以符合某一正则限定的格式
expect( ( matches(\"[1-9][0-9]\\{4,\\}\")) ).andReturn(\"2\");
replay
在生成 Mock 对象和设定 Mock 对象行为两个阶段,Mock 对象的状态都是 Record 。在这个阶段,Mock 对象会记录用户对预期行为和输出的设定。
在使用 Mock 对象进行实际的测试前,我们需要将 Mock 对象的状态切换为 Replay。在 Replay 状态,Mock 对象能够根据设定对特定的方法调用做出预期的响应。
replay( service );
Verify
在利用 Mock 对象进行实际的测试过程之后,为了验证指定的方法调用真的完成了,我们需要调用 verify 方法进行验证。
verify( service );
因篇幅问题不能全部显示,请点此查看更多更全内容