最新软件测试实验单元测试工具JUNIT.docx
《最新软件测试实验单元测试工具JUNIT.docx》由会员分享,可在线阅读,更多相关《最新软件测试实验单元测试工具JUNIT.docx(24页珍藏版)》请在冰豆网上搜索。
最新软件测试实验单元测试工具JUNIT
武汉轻工大学
软件测试实验报告
实验一单元测试工具JUNIT
姓名:
李娅娅
学号:
1505110015
班级:
软工1503
指导老师:
丁月华
1.实验目的
了解自动化测试工具JUnit的架构、功能,学习如何下载、安装JUnit,掌握使用JUnit对Java程序进行单元测试的方法。
2.实验步骤
2.1导入jar包
右击项目名,单击BuildPath中的AddLibraries..
选择UserLibariry。
新建一个存放Junit的包的库
将junit-4.7.jar导入
Jar包导入完成。
2.2编写第一个Junit测试类
2.2.1Calculator类
编写被测试类Calculator:
(拷贝)
privatestaticintresult;//静态变量,用于存储运行结果
publicvoidadd(intn){
result=result+n;
}
publicvoidsubstract(intn){
result=result-1;//Bug:
正确的应该是result=result-n
}
publicvoidmultiply(intn){
}//此方法尚未写好
publicvoiddivide(intn){
result=result/n;
}
publicvoidsquare(intn){
result=n*n;
}
publicvoidsquareRoot(intn){
for(;;);//Bug:
死循环
}
publicvoidclear(){//将结果清零
result=0;
}
publicintgetResult(){
returnresult;
}
}
2.2.2CalculatorTest类
编写CalculatorTest类,用于测试Calculator类:
(拷贝)
publicclassCalculatorTest{
privatestaticCalculatorcalculator=newCalculator();
@Before
publicvoidsetUp()throwsException{
calculator.clear();
}
@Test
publicvoidtestAdd(){
calculator.add
(2);
calculator.add(3);
assertEquals(5,calculator.getResult());
}
@Test
publicvoidtestSubstract(){
calculator.add(10);
calculator.substract
(2);
assertEquals(8,calculator.getResult());
}
@Ignore("Multiply()Notyetimplemented")
@Test
publicvoidtestMultiply(){
}
@Test
publicvoidtestDivide(){
calculator.add(8);
calculator.divide
(2);
assertEquals(4,calculator.getResult());
}
}
2.2.3运行测试
在类名上右击,选择RunAs→JunitTest
得到Junit面板,并显示了哪些测试是成功的,哪些是失败的以及哪些是未执行(直接跳过了):
2.3使用JUnit对Money类进行单元测试
2.3.1Money类
(拷贝)
publicclassMoney{
privateintfAmount;//货币余额
privateStringfCurrency;//货币类型
publicMoney(intamount,Stringcurrency){
fAmount=amount;
fCurrency=currency;
}
publicintamount(){
returnfAmount;
}
publicStringcurrency(){
returnfCurrency;
}
publicMoneyadd(Moneym){
//add方法把两个Money对象相加,合成一个Money对象
returnnewMoney(amount()+m.amount(),currency());
}
publicbooleanequals(ObjectanObject){
//equals方法判断两个Money对象是否相等
if(anObjectinstanceofMoney){
MoneyaMoney=(Money)anObject;
returnaMoney.currency().equals(currency())&&amount()==aMoney.amount();
}
returnfalse;
}
}
现在要对Money类的add方法进行测试,步骤如下:
2.3.2MoneyTest类
(1)创建对象
定义几个Money类的对象
Moneyresult;
Moneym12CHF=newMoney(12,"CHF");
Moneym14CHF=newMoney(14,"CHF");
Moneyexpected=newMoney(26,"CHF");//预期的运行结果
(2)addTest()
在MoneyTest类中编写testAdd方法,对Money类中的add()方法进行测试:
@Test
publicvoidtestAdd(){
result=m12CHF.add(m14CHF);
assertTrue(expected.equals(result));//判断运行结果是否与预期值相同
}
(3)testEquals()
@Test
publicvoidtestEquals()
{
assertTrue(!
m12CHF.equals(null));
assertTrue(!
m12CHF.equals(m14CHF));
assertEquals(m12CHF,m12CHF);
assertEquals(m12CHF,newMoney(12,"CHF"));
}
2.3.3运行测试
测试通过
2.4Fixture和几个标签
Fixture的含义就是“在某些阶段必然被调用的代码”。
比如我们上面的测试,由于只声明了一个Calculator对象,他的初始值是0,但是测试完加法操作后,他的值就不是0了;接下来测试减法操作,就必然要考虑上次加法操作的结果。
这绝对是一个很糟糕的设计!
我们非常希望每一个测试都是独立的,相互之间没有任何耦合度。
因此,我们就很有必要在执行每一个测试之前,对Calculator对象进行一个“复原”操作,以消除其他测试造成的影响。
因此,“在任何一个测试执行之前必须执行的代码”就是一个Fixture,我们用@Before来标注它,如前面例子中的setUp()方法所示:
这里不在需要@Test标注,因为这不是一个test,而是一个Fixture。
同理,如果“在任何测试执行之后需要进行的收尾工作”也是一个Fixture,使用@After来标注。
2.4.1代码测试
publicclassTTest{
@BeforeClass
publicstaticvoidbeforeClass(){
System.out.println("beforeClass");
}
@AfterClass
publicstaticvoidafterClass(){
System.out.println("afterClass");
}
@Before
publicvoidbefore(){
System.out.println("before");
}
@Test
publicvoidtestAdd(){
intz=newT().add(5,3);
assertThat(z,is(8));
assertThat(z,allOf(greaterThan(5),lessThan(10)));
}
@Test(expected=java.lang.ArithmeticException.class,timeout=100)
publicvoidtDivide(){
intz=newT().divide(8,0);
}
@After
publicvoidafter(){
System.out.println("after");
}
}
2.4.2运行结果
在控制台中得到运行结果:
在Junit选型卡中得到:
(1)结果分析
在Junit选项卡中由于代码找不到T类,而使方法运行错误。
在控制台中输出两次before和两次after,是因为在类中test了两个方法,每运行一个方法,@before和@after下的方法就是默认执行。
2.4.3标签学习
(1)@Test
测试方法
(2)@Before
使用了该元数据的方法在每个测试方法执行之前都要执行一次,一般做初始化方法。
(3)@After
使用了该元数据的方法在每个测试方法执行之后要执行一次,一般用于释放资源。
(4)@ignore
该元数据标记的测试方法在测试中会被忽略。
你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。
比如:
@lgnore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
(5)@BeforeClass
所有测试开始之前运行,一个测试类只能有一个,并且必须声明为publicstatic。
该方法在内存中只存在一份实例,比较适合加载配置文件。
(6)@AfterClass:
所有测试结束之后运行 ,一个测试类只能有一个,并且必须声明为publicstatic。
通常用来对资源进行清理,比如关闭数据库的连接。
(备注:
为什么需要@BeforeClass和@AfterClass,我们来看看他们是否适合完成如下功能:
有一个类是负责对大文件(超过500兆)进行读写,他的每一个方法都是对文件进行操作。
换句话说,在调用每一个方法之前,我们都要打开一个大文件并读入文件内容,这绝对是一个非常耗费时间的操作。
如果我们使用@Before和@After,那么每次测试都要读取一次文件,效率及其低下。
这里我们所希望的是在所有测试一开始读一次文件,所有测试结束之后释放文件,而不是每次测试都读文件。
JUnit的作者显然也考虑到了这个问题,它给出了@BeforeClass和@AfterClass两个Fixture来帮我们实现这个功能。
从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例初始化时执行@BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。
)
JUnit4的单元测试用例执行顺序为:
@BeforeClass->@Before->@Test->@After->@AfterClass。
每一个测试方法的调用顺序为:
@Before->@Test->@After。
可以根据以上给定的标记来构造测试类中的测试方法,一般说来遵守以下约定:
类放在test包中
类名用XXXTest结尾
方法用testMethod命名
2.5限时测试
@Test(timeout=value),例如@Test(timeout=1000)
2.5.1被测源代码
2.5.2测试代码
@Test(timeout=1000)
publicvoidtestSquareRoot(){
calculator.squareRoot(4);
assertEquals(2,calculator.getResult());
}
2.5.3运行测试
在测试代码中Timeout参数表明了设定的时间,单位为毫秒,因此1000就代表1秒,测试的方法超过了设定的时间表示失败。
2.6异常测试
对除法运算中的“除0异常”进行测试
2.7综合练习
2.7.1测试代码
publicclassCalculatorTest{
privatestaticCalculatorcalculator=newCalculator();
@BeforeClass
publicstaticvoidbeforeClass(){
System.out.println("beforeClass");
}
@AfterClass
publicstaticvoidafterClass(){
System.out.println("afterClass");
}
@Before
publicvoidbefore(){
System.out.println("before");
}
@After
publicvoidafter(){
System.out.println("after");
}
@Before
publicvoidsetUp()throwsException{
calculator.clear();
}
@Test
publicvoidtestAdd(){
calculator.add
(2);
calculator.add(3);
assertEquals(5,calculator.getResult());
}
@Test
publicvoidtestSubstract(){
calculator.add(10);
calculator.substract
(2);
assertEquals(8,calculator.getResult());
}
@Ignore("Multiply()Notyetimplemented")
@Test
publicvoidtestMultiply(){
}
@Test
publicvoidtestDivide(){
calculator.add(8);
calculator.divide
(2);
assertEquals(4,calculator.getResult());
}
@Test(timeout=1000)
publicvoidtestSquareRoot(){
calculator.squareRoot(4);
assertEquals(2,calculator.getResult());
}
@Test(expected=ArithmeticException.class)
publicvoiddivideByZero(){
calculator.divide(0);
}
}
2.7.2运行测试
(1)控制台
分析:
在代码中定义了@BeforeClass和@AfterClass标签,因此,在输出的首尾有这标签下定义的输出信息。
代码中编写了6个测试方法,因此对@Before,@After标签下的输出信息打印了5遍(其中方法testMultiply使用了@Ignore标签)。
(2)Junit选项卡
测试结果为三个通过,一个忽略,一个失败,一个错误。
2.8运行器@RunWith
当把测试代码提交给JUnit框架后,框架就会通过Runner来运行代码。
在JUnit中有很多个Runner,他们负责调用测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。
JUnit中有一个默认Runner,如果你没有指定,那么系统自动使用默认Runner来运行你的代码。
也就是说,下面两段代码含义是完全一样的:
publicclassCalculatorTest{...}//该方式就是使用了默认的Runner
等价于
@RunWith(JUnit4ClassRunner.class)
publicclassCalculatorTest{...}//声明了Runner
从上述例子可以看出,要想指定一个Runner,需要使用@RunWith标注,并且把你所指定的Runner作为参数传递给它。
另外一个要注意的是,@RunWith是用来修饰类的,而不是用来修饰函数的。
只要对一个类指定了Runner,那么这个类中的所有函数都被这个Runner来调用。
是对其他Runner的学习:
2.8.1参数化测试@RunWith(Parameterized.class)
把一组组的测试数据集中放在一个集合中,这个集合作为测试类的参数,进行集中测试,避免为每一组测试数据写一个测试方法。
你可能遇到过这样的函数,它的参数有许多特殊值,或者说他的参数分为很多个区域。
比如,一个对考试分数进行评价的函数,返回值分别为“优秀,良好,一般,及格,不及格”,因此你在编写测试的时候,至少要写5个测试,把这5中情况都包含了,这确实是一件很麻烦的事情。
我们还使用我们先前的例子,测试一下“计算一个数的平方”这个函数,暂且分三类:
正数、0、负数。
(1)测试代码
按照之前的方法,要测试三类就需要编写三个测试方法:
publicclassAdvancedTest{
privatestaticCalculatorcalculator=newCalculator();
@Before
publicvoidclearCalculator(){
calculator.clear();
}
@Test
publicvoidsquare1(){
calculator.square
(2);
assertEquals(4,calculator.getResult());
}
@Test
publicvoidsquare2(){
calculator.square(0);
assertEquals(0,calculator.getResult());
}
@Test
publicvoidsquare3(){
calculator.square(-3);
assertEquals(9,calculator.getResult());
}
}
运行结果:
为了简化类似的测试,JUnit4提出了“参数化测试”的概念,只写一个测试函数,把这若干种情况作为参数传递进去,一次性的完成测试。
代码如下:
@RunWith(Parameterized.class)//更改默认的测试运行器为Parameterized.class
publicclassSquareTest{
privatestaticCalculatorcalculator=newCalculator();
privateintparam;//声明变量存放输入参数(用来计算实际结果)
privateintresult;//声明变量存放预期值
//声明一个返回值为Collection的公共静态方法,并用@Parameters修饰
@Parameters
publicstaticCollectiondata(){
returnArrays.asList(newObject[][]{{2,4},{0,0},{-3,9}});
}
//为测试类声明一个带有参数的公共构造方法,并为声明变量赋值
publicSquareTest(intparam,intresult){
this.param=param;
this.result=result;
}
@Test
publicvoidsquare(){
calculator.square(param);
assertEquals(result,calculator.getResult());
}
}
5、就业机会和问题分析分析:
首先,要为这种测试专门生成一个新的类,而不能与其他测试共用同一个类,此例中我们定义了一个SquareTest类。
然后,你要为这个类指定一个Runner,而不能使用默认的Runner了,因为特殊的功能要用特殊的Runner。
@RunWith(Parameterized.class)这条语句就是为这个类指定了一个ParameterizedRunner。
动漫书籍□化妆品□其他□第二步,定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。
接下来,定义测试数据的集合,也就是上述的data()方法,该方法可以任意命名,但是必须使用@Parameters标注进行修饰。
之后是构造函数,其功能就是对先前定义的两个参数进行初始化。
(2)测试结果
朋友推荐□宣传广告□逛街时发现的□上网□2.8.2测试套件@RunWith(Suite.class)
通过前面的案例学习到,在一个项目中,只写一个测试类是不可能的,我们会写出很多很多个测试类。
可是这些测试类必须一个一个的执行,也是比较麻烦的事情。
鉴于此,JUnit为我们提供了打包测试的功能,将所有需要运行的测试类集中起来,一次性的运行完毕,大大的方便了我们的测试工作。
具体测试套件代码如下:
(1)测试代码
@RunWith(Suite.class)
@Suite.SuiteClasses({CalculatorTest.class,SquareTest.class})
//测试套件的入口类,该类不包含任何方法,
//更改测试运行器Suite.class,将测试类作为数组传入到Suite.SuiteClasses({});
publicclassSuiteTest{
5、你认为一件DIY手工艺制品在什么价位可以接受?
(5)资金问题}
这个测试代码表示将CalculatorTest.class和SquareTest.class同时进行测试。
运行测试,可以看到两个测试类的测试结果:
(2