
实 验 报 告
(2014 / 2015 学年 第一学期)
| 课程名称 | 软件工程(双语) | |||||
| 实验名称 | 软件单元测试 | |||||
| 实验时间 | 2014 | 年 | 12 | 月 | 9 | 日 |
| 指导单位 | 计算机学院软件工程系 | |||||
| 指导教师 | 宗平 | |||||
| 学生姓名 | 楚灵翔 | 班级学号 | B12040731 |
| 学院(系) | 计算机软件学院 | 专 业 | 软件工程 |
| 实验名称 | 软件单元测试 | 指导教师 | 宗平 | |||
| 实验类型 | 上机 | 实验学时 | 2 | 实验时间 | 2014.12.9 | |
| 一、实验目的和要求 内容:要求学生能够完成单元测试的设计和运行。 要求:能正确进行黑盒测试和白盒测试的测试用例设计。 | ||||||
| 二、实验环境(实验设备) 硬件:微机 软件:win7操作系统,MyEclipse(Java)编程软件 | ||||||
| 三、实验原理及内容 参考《实验三:Software Unit Testing 实验指导书》,了解Java单元测试,学会使用Junit编写自己的测试用例,并对被测试类进行测试。 1、阅读Junit的工作机制,了解单元测试、黑盒测试和白盒测试。(资料均来自CSDN博客) (一)相关概念 黑盒测试——把测试对象看作一个封闭的盒子,针对程序的功能来设计测试数据。 白盒测试——把测试对象看作一个打开的盒子,程序内部的逻辑结构和其他信息对测试人员是公开的。 回归测试——软件或环境的修复或更正后的“再测试”,自动测试工具对这类测试尤其有用。 单元测试——是最小粒度的测试,以测试某个功能或代码块。一般由程序员来做,因为它需要知道内部程序设计和编码的细节。 | ||||||
| JUnit ——是一个开发源代码的Java测试框架,用于编写和运行可重复的测试。他是用于单元测试框架体系xUnit的一个实例(用于java语言)。主要用于白盒测试,回归测试。 (二)Junit入门简介 (1)JUnit的好处和JUnit单元测试编写原则 好处: A、可以使测试代码与产品代码分开。 B、针对某一个类的测试代码通过较少的改动便可以应用于另一个类的测试。 C、易于集成到测试人员的构建过程中,JUnit和Ant的结合可以实施增量开发。 D、JUnit是公开源代码的,可以进行二次开发。 E、可以方便地对JUnit进行扩展。 编写原则: A、是简化测试的编写,这种简化包括测试框架的学习和实际测试单元的编写。 B、是使测试单元保持持久性。 C、是可以利用既有的测试来编写相关的测试。 (2)JUnit的特征 A、使用断言方法判断期望值和实际值差异,返回Boolean值。 B、测试驱动设备使用共同的初始化变量或者实例。 C、测试包结构便于组织和集成运行。 D、支持图型交互模式和文本交互模式。 (3)JUnit框架组成 A、对测试目标进行测试的方法与过程集合,可称为测试用例(TestCase)。 B、测试用例的集合,可容纳多个测试用例(TestCase),将其称作测试包(TestSuite)。 C、测试结果的描述与记录。(TestResult) 。 D、测试过程中的事件监听者(TestListener)。 E、每一个测试方法所发生的与预期不一致状况的描述,称其测试失败元素(TestFailure) F、JUnit Framework中的出错异常(AssertionFailedError)。 JUnit框架是一个典型的Composite模式:TestSuite可以容纳任何派生自Test的对象;当调用TestSuite对象的run()方法是,会遍历自己容纳的对象,逐个调用它们的run()方法。(可参考《程序员》2003-6期)。 2、MyEclipse环境下的单元测试实验 (1)依据示例的过程截图如下,代码略。 首先要创建(或选择)自己的工作空间: | ||||||
接下来创建并编写UnitTest类:
点击右键,新建类:
点击完成后,打开类,写入代码,然后再建测试用例:
选择其中任一方法作为测试对象,这里选取的是equals()方法。
结果如下:
(2)为Triangle类编写测试用例:
将一些要点的截图以及代码提供如下。
点击完成,创建Triangle类。代码如下:
package cn.edu.njupt;
public class Triangle {
// 定义三角形的三边
protected long lborderA = 0;
protected long lborderB = 0;
protected long lborderC = 0;
// 构造函数
public Triangle(long lborderA, long lborderB, long lborderC) {
this.lborderA = lborderA;
this.lborderB = lborderB;
this.lborderC = lborderC;
}
/**
* 判断是否是三角形。是返回ture;不是返回false
*/
public static boolean isTriangle(Triangle triangle) {
boolean isTriangle = false;
// 判断边界,大于0 小于或等于Long.MAX_VALUE,出界返回false
if ((triangle.lborderA > 0 && triangle.lborderA <= Long.MAX_VALUE / 2)
&& (triangle.lborderB > 0 && triangle.lborderB <= Long.MAX_VALUE / 2)
&& (triangle.lborderC > 0 && triangle.lborderC <= Long.MAX_VALUE / 2)){
// 判断两边之和大于第三边
if ((triangle.lborderA < (triangle.lborderB + triangle.lborderC))
&& (triangle.lborderB < (triangle.lborderA + triangle.lborderC))
&& (triangle.lborderC < (triangle.lborderA + triangle.lborderB))){
isTriangle = true;
}
}
return isTriangle;
}
/**
* 判断三角形类型
* 只有两条边相等的三角形返回字符串“等腰三角形”;
*三边均相等的三角形返回字符串“等边三角形”;
* 三边均不等的三角形返回字符串“不等边三角形”;
*/
public static String getType(Triangle triangle) {
String strType = "不是三角形 ";
// 判断是否是三角形
if (isTriangle(triangle)) {
// 判断是否是等边三角形
if (triangle.lborderA == triangle.lborderB
&& triangle.lborderB == triangle.lborderC) {
strType = "等边三角形";
}
// 判断是否是不等边三角形
else if ((triangle.lborderA != triangle.lborderB)
&& (triangle.lborderB != triangle.lborderC)
&& (triangle.lborderA != triangle.lborderC)) {
strType = "不等边三角形";
}
// 三角形既非三边全部相等,又非全部不等,只能是部分相等即等腰三角形
else {
strType = "等腰三角形";
}
}
return strType;
}
}
下面创建测试用例:
选择要测试的方法:
我将两种方法一起测试以作比较。但是建议一个测试用例只对一种方法测试。
写入代码如下:
package cn.edu.njupt;
import junit.framework.TestCase;
public class TriTest extends TestCase {
private Triangle tri1;
private Triangle tri2;
private Triangle tri3;
public TriTest(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
super.setUp();
tri1=new Triangle(3,4,5);
tri2=new Triangle(4,4,4);
tri3=new Triangle(6,5,5);
}
protected void tearDown() throws Exception {
super.tearDown();
tri1=null;
tri2=null;
tri3=null;
}
public void testIsTriangle() {
assertTrue(Triangle.isTriangle(tri1));
assertTrue(Triangle.isTriangle(tri2));
assertTrue(Triangle.isTriangle(tri3));
assertFalse(!Triangle.isTriangle(tri1));
assertFalse(!Triangle.isTriangle(tri2));
assertFalse(!Triangle.isTriangle(tri3));
}
public void testGetType() {
assertNotNull(Triangle.getType(tri1));
assertNotNull(Triangle.getType(tri2));
assertNotNull(Triangle.getType(tri3));
}
}
点击运行,结果会因为实例的不同而不同:
tri2=new Triangle(4,4,4);
tri3=new Triangle(6,5,5);
通过上图对比可知,两个方法之间是相互的。
3、补充介绍Junit断言和最佳实践。
(1)Junit断言简介:(都继承自Assert超类)
|- assertEquals(a, b)
Asserts that two primitive values are equal.
测试a是否等于b(a和b是原始类型数值(primitive value)或者必须为实现比较而具有equal方法)
|- assertFalse(a)
Asserts that a condition (a) is false.
测试a是否为false(假),a是一个Boolean数值。
|- assertTrue(a)
Asserts that a condition is true.
测试a是否为true(真),a是一个Boolean数值
|- assertNotNull(a)
Asserts that an object isn't null.
测试a是否非空,a是一个对象或者null。
| |- assertNull(a) | |||||
| Asserts that an object is null. 测试a是否为null,a是一个对象或者null。 |- assertNotSame(a, b) Asserts that two objects do not refer to the same object. 测试a和b是否没有都引用同一个对象。 |- assertSame(a, b) Asserts that two objects refer to the same object. 测试a和b是否都引用同一个对象。 |- fail(message) 当程序错误时候,输出错误消息 |-自定义断言 通常而言,JUnit所提供的标准断言对大多数测试已经足够了。然而,在某些环境下,我们可能更需要自定义一些断言来满足我们的需要。 通常的做法是定义一个TestCase的子类,并且使用这个子类来满足所有的测试。新定义的共享的断言或者公共代码放到这个子类中。 (2)Junit最佳实践: |- 一次只有一个测试对象:(当无法预计这些对象发生改变时不会造成相互影响) |- 选择有一个的测试方法名:testXxx命名模式(Xxx为待测方法)。若在同一个方法增添其他测试testXxxYyy的命名模式 |- Assert调用总解释失败原因。第一个参数务必为描述文本 |- setUp方法用来实例化DefaultController. Junit会在调用其他之前调用 |- 一个单元测试等于一个测试方法(简介、专注) |- 测试任何可能失败的事务 |- 让测试改善代码 编写单元测试常常有助有你写出更好的代码。理由很简单:test case是你代码的用户只有在使用代码时才能发现代码的缺点。所以,不要犹豫,应当根据测试时发现的不使之处重构代码,使其易于使用。测试驱动开发(TDD)的实践就依赖于这条原则。通过先编写测试,你就可以从用户的角度来开发你的类。 |- 让异常测试易懂。把case块中异常变量命名为expected |- 同一个包,分离目录 | |||||
| 四、实验小结(包括问题和解决方法、心得体会、意见与建议等) 本次实验让我们学会完成单元测试的设计和运行,能正确进行黑盒测试和白盒测试的测试用例设计。 在MyEclipse IDE环境中,有一些快捷键应当熟悉。在编写测试用例过程中,形成良好的测试习惯。 这次实验让我知道,在软件测试过程中,我们现在学习的的还仅仅是皮毛,需要多看看课外的东西。 | |||||
| 五、指导教师评语
| |||||
| 成 绩 | 批阅人 | 日 期 | |||
