目 录
一、实验学时
2学时
二、实验目的
1.系统学习和理解单元测试的基本概念、原理。
2.掌握单元测试的基本技术和方法。
3.掌握在Eclipse里面进行JUnit单元测试的基本流程与使用方法。
4.掌握EclEmma代码覆盖测试工具的使用。
5.理解JUnit4中几个注解:@Before、@After、@Test、@Ignore、@BeforeClass、@AfterClass的用法及执行次序。
三、实验环境
(一)硬件环境:
1.笔记本电脑一台
2.内存大小:64G
3.磁盘空间:1TB
(二)软件环境:
1.操作系统:Windows(64位)11
2.文本撰写:WPS
3.软件工具:Eclipse、JUnit、Eclemma
四、实验内容
1、实验方案:
在Eclipse中,安装JUnit单元测试框架和Eclemma代码覆盖率工具,为代码的全面测试和分析打下基础。创建一个Java项目并编写所需类,实现根据年份和月份返回对应天数的方法。运用黑盒测试和白盒测试的原理,设计全面的测试用例,确保所有可能的输入情况都被覆盖。利用JUnit编写测试类,并使用注解和断言方法进行测试,详细记录并分析测试结果。
完成测试后,借助Eclemma插件深入分析代码覆盖率,查看哪些代码行被测试覆盖,哪些未覆盖,并根据分析结果调整测试用例或代码,以进一步提高覆盖率。通过以上步骤,我们将完成函数的编写、测试及代码覆盖率分析,确保代码的质量和稳定性得到充分的验证。
2、实验步骤:
(1)在Eclipse中安装JUnit单元测试框架和Eclemma代码覆盖率工具。
(2)利用Eclipse编写函数,根据提供的年份和月份,返回该月的天数。
(3)运用黑盒测试方法或白盒测试方法设计该函数的测试用例。
(4)利用JUnit完成整个函数的测试过程,并记录并分析测试结果。
(5)使用Eclemma分析单元测试代码的覆盖率情况。
(6)完成实验报告的书写及提交工作。
3、设计思路:
1、安装 JUnit 和Eclemma
将JUnit和Eclemma集成到Eclipse中,以便进行单元测试和代码覆盖率分析。
2、编写函数
在Eclipse中创建一个新的Java项目,编写一个方法,接收年份和月份作为参数,并返回对应月份的天数。
3、设计测试用例
采用黑盒测试或白盒测试中的等价类划分、边界值分析、错误推测等方法来设计测试用例。
- 通过等价类划分将输入字段划分为有效和无效两类,然后针对每类设计测试用例。
- 通过边界值分析测试输入字段的边界值。
- 通过错误推测预测可能出现的错误情况并设计相应的测试用例。
4、编写 JUnit 测试
在Eclipse中创建一个JUnit测试类,编写测试方法,针对函数的各种情况编写测试用例,并使用断言来验证函数的行为是否符合预期。
5、运行测试并分析结果
在Eclipse中运行JUnit测试,观察测试结果,检查测试是否通过,并记录失败的测试用例以进行调试和修复。
6、使用Eclemma进行代码覆盖率分析
使用Eclemma工具分析JUnit测试的代码覆盖率,查看代码覆盖率报告,确定哪些部分的代码没有被测试到,并根据需要更新测试用例以提高代码覆盖率。
7、审查和修订
完成测试用例的编写后,需要进行审查和修订。包括检查测试用例的完整性、准确性和可执行性,确保它们能够全面覆盖测试目标和范围。同时,还需要根据实际需求和技术变化对测试用例进行更新和调整。
通过以上步骤,可以系统地设计针对所编写函数的测试用例,以确保测试工作的有效性和高效性。
五、实验结果
1、 安装 JUnit 和Eclemma
(1)JUnit单元测试框架安装
- 打开Eclipse后点击菜单栏中的File,在下拉菜单中选择New并点击,然后点击出现的Java Project进行Java项目的创建,如图1-1-1所示:

图1-1-1 Java项目创建界面1
- 输入项目名称为"YLW_JUnit"后点击Next进入下一步后点击Finish完成项目的创建,如图1-1-2所示:

图1-1-2 Java项目创建界面2
- 使用鼠标右击刚才创建的项目,然后点击菜单最下方的"Properties",如图1-1-3所示:

图1-1-3 JUnit单元测试框架安装界面1
- 在新的窗口中点击"Java Build Path"后选择"Libraries"中的"Modulepath",再点击"Add Library"进行JUnit单元测试框架的安装,如图1-1-4所示:

图1-1-4 JUnit单元测试框架安装界面2
- 在"Add Library"窗口中选择"JUnit"后点击Next进入下一步后再点击下拉菜单选择"JUnit5"后点击Finish完成JUnit5数据包的载入,如图1-1-5所示:

图1-1-5 JUnit单元测试框架添加界面1
- JUnit数据包添加完毕后点击界面右下角的"Apply"进行应用,或者直接点击"Apply and Close"应用并关闭,如图1-1-6所示:

图1-1-6 JUnit单元测试框架添加界面2
- 当JUnit单元测试框架安装完毕后,会在对应的库中存在相关的一系列JAR文件,如图1-1-7所示:

图1-1-7 JUnit单元测试框架添加成功界面
(2)Eclemma代码覆盖率工具安装
- 打开Eclipse后点击菜单栏中的Help,在下拉菜单中点击Eclipse Marketplace,如图1-2-1所示:

图1-2-1 Eclemma代码覆盖率工具安装界面1
- 在弹出的窗口搜索栏输入"EclEmma"后点击回车,如图1-2-2所示:

图1-2-2 Eclemma代码覆盖率工具安装界面2
- 滑动滚轮找到"EclEmma Java Code Coverage 3.1.8"点击安装即可,如图1-2-3所示:

图1-2-3 Eclemma代码覆盖率工具安装界面3
2、 利用Eclipse编写函数
(1)右击项目的"Src文件夹"后点击"New"会出现子目录,在子目录中点击"Class"创建"ReturnDay.java"Java类文件,如图2-1所示:

图2-1 Java类文件创建界面1
(2)在弹出的窗口中填写对应的类名后点击界面右下角的Finish按钮即可完成对应Java类文件的创建,如图2-2所示:

图2-2 Java类文件创建界面2
(3)在"ReturnDay.java"类文件中编写函数,使其可以根据所提供的年份和月份返回对应月份的天数,如图2-3所示:

图2-3 Java类文件执行结果界面
函数代码:
java
import java.util.Scanner;
// 返回当月天数的类
public class ReturnDay {
// 返回当月天数的方法体(年份,月份)
public static int getDaysInMonth(int year, int month) {
if (year <= 0 || String.valueOf(year).contains("+")) {
System.out.println("年份输入错误,请输入正确的年份(正整数)!");
return 0;
}
if (month <= 1 || month >= 12) {
System.out.println("月份输入错误,请重新输入正确的月份(1至12月)!");
return 0;
}
// 初始化天数为0
int days = 0;
// 月份判断
switch (month) {
// 1、3、5、7、8、10、12月份为每一年的大月,当月为31天
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
days = 31;
break;
// 4、6、9、11月份为每一年的小月,当月为30天
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
// 2月闰年29天,平年是28天(4年一闰)
case 2:
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
days = 29;
} else {
days = 28;
}
break;
default:
System.out.println("数据信息错误,无法返回对应天数!");
}
return days;
}
// 主函数
public static void main(String[] args) {
// 初始化输入
Scanner scanner = new Scanner(System.in);
String StringInput = "Y";
while (StringInput.equals("Y")) {
System.out.print("请输入所需年份:");
while (!scanner.hasNextInt()) {
System.out.println("年份输入错误,请输入正确的年份(非整数)!");
scanner.next();
}
int year = scanner.nextInt();
System.out.print("请输入所需月份:");
while (!scanner.hasNextInt()) {
System.out.println("月份输入错误,请输入正确的月份(非整数)!");
scanner.next();
}
int month = scanner.nextInt();
if (month < 1 || month > 12) {
System.out.println("月份输入错误,请重新输入正确的月份(1至12月)!");
continue;
}
int days = getDaysInMonth(year, month);
System.out.println(year+"年"+month+"月有:"+days+"天");
System.out.println("");
System.out.println("是否继续进行输入? (Y/N): ");
StringInput = scanner.next();
}
scanner.close();
}
}
3 、 测试用例编写
(1) 正向测试用例
正向测试用例是用来验证函数在给定有效输入时是否产生预期的输出,测试函数的各种预期用法,并确保函数对于标准输入提供正确的响应。
表3-1正向测试用例
(2)反向测试用例
反向测试用例是用来验证函数在给定无效输入或异常情况下的行为是否正确,测试函数对于异常情况的处理方式,包括错误检测和错误消息的生成。确保函数在面对非预期输入时能够适当地处理,而不会导致系统崩溃或不正确的行为。
表3-2反向测试用例
4 、 利用JUnit进行测试
(1)右击"ReturnDay.java"类文件后点击"New"在子菜单中选择"JUnit Test Case"进行测试用例的创建,如图4-1所示:

图4-1 测试用例类文件创建界面1
(2)在"JUnit Test Case"界面输入类文件的名称为"ReturnDayTest"后勾选所需要创建的函数选项并点击Next进入下一步,如图4-2所示:

图4-2 测试用例类文件创建界面2
(3)进入新界面后选择需要进行测试的函数,勾选后点击Finish按钮即可完成对应测试类函数的创建工作,如图4-3所示:

图4-3 测试用例类文件创建界面3
(4)测试用例类文件创建完毕后在类中添加对应的测试用例方法进行函数的覆盖化测试,如图4-4所示:

图4-4 测试用例类文件编写界面
测试用例代码:
java
import org.junit.Test;
import static org.junit.Assert.*;
public class ReturnDayTest {
@Test
public void test_R1_T() {
// 测试闰年的2月份天数
int year = 2020;
int month = 2;
int expectedDays = 29;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_P1_T() {
// 测试平年的2月份天数
int year = 2021;
int month = 2;
int expectedDays = 28;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_R2_Min() {
// 测试闰年小月的天数
int year = 2020;
int month = 4;
int expectedDays = 30;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_P2_Min() {
// 测试平年小月的天数
int year = 2021;
int month = 4;
int expectedDays = 30;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_R3_Max() {
// 测试闰年大月的天数
int year = 2020;
int month = 8;
int expectedDays = 31;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_P3_Max() {
// 测试平年大月的天数
int year = 2021;
int month = 8;
int expectedDays = 31;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_4_FY() {
// 测试非法年份(0)
int year = -2021;
int month = 4;
int expectedDays = 0;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_4_FM() {
// 测试非法月份(0)
int year = 2020;
int month = -4;
int expectedDays = 0;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_5_FM() {
// 测试非法月份(0)
int year = 2021;
int month = 0;
int expectedDays = 0;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_6_FM() {
// 测试非法月份(0)
int year = 2020;
int month = 13;
int expectedDays = 0;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_7_FY() {
// 测试非法年份(0)
int year = +2021;
int month = 4;
int expectedDays = 0;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_8_TY() {
// 测试特殊年份2月的天数(2000)
int year = 2000;
int month = 2;
int expectedDays = 29;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
@Test
public void test_9_TY() {
// 测试特殊年份2月的天数
int year = 1000;
int month = 2;
int expectedDays = 28;
int actualDays = ReturnDay.getDaysInMonth(year, month);
assertEquals(expectedDays, actualDays);
}
}
(5)测试用例方法全部添加完毕后可以进行测试用例的运行操作,右击主界面后点击"Run As"再选择"JUnit Test"进行测试用例的运行,如图4-5所示:

图4-5 测试用例类文件运行界面
(6)测试用例运行完毕后即可查看对应的相关测试用例覆盖率等数据信息,如图4-6所示:

图4-6 测试用例类文件运行结果界面
5 、 利用Eclemma进行覆盖率分析
(1)点击界面左上角运行按钮旁边的覆盖运行按钮即可对覆盖率进行对应的分析,如图5-1所示:

图5-1 测试用例类文件覆盖率分析运行界面
(2)运行后点击菜单栏中的"Windows"并选择"Show View"后点击"Other"进入到对应界面,如图5-2所示:

图5-2 测试用例类文件覆盖率查看过程界面1
(3)在新界面的输入框中输入"coverage"后回车,选择出现的"Coverage"文件并点击窗口右下角的"Open"按钮进行打开,如图5-3所示:

图5-3 测试用例类文件覆盖率查看过程界面2
(4)打开后即可查看到相关的所有覆盖率详情信息,如图5-4所示:

图5-4 测试用例类文件覆盖率查看界面
(5)覆盖率分析查看完毕后进行相关的覆盖率报告的导出工作,点击菜单栏中的"File"后选择"Export"进入到对应的界面,如图5-5所示:

图5-5 测试用例覆盖率报告导出界面1
(6)进入新界面后点击"Run/Debug"并选择"Coverage Session"后点击Next进入下一步,如图5-6所示:

图5-6 测试用例覆盖率报告导出界面2
(7)在新界面中选择导出方式为"HTML"和导出的位置,点击Finish后即可完成对应覆盖率报告的导出工作,如图5-7所示:

图5-7 测试用例覆盖率报告导出界面3
(8)在指定的导出位置即可看见导出后的HTML文件,点击对应的HTML文件就可以看到对应的所有覆盖率数据信息,如图5-8所示:

图5-8-1 测试用例覆盖率报告界面1

图5-8-2 测试用例覆盖率报告界面2

图5-8-3 测试用例覆盖率报告界面3
六、实验小结(包括问题和解决办法、心得体会、意见与建议等)
1、实验问题及解决方法:
1)实验问题:对返回当月天数函数的单元测试的需求理解不清楚。
解决方法:仔细分析函数,可以参考其他类似的实现方式,以帮助理解具体的细节。
2)实验问题:单元测试用例书写不熟练,导致用例撰写效率低下。
解决方法:了解单元测试的基本步骤和示例,通过实际操作和练习,逐渐提高对单元测试用例撰写的熟练度。
3)实验问题:在设计单元测试用例时遇到了边界条件的处理困难。
解决方法:采用边界值分析和等价类划分等测试方法,对系统的边界条件进行明确化,即确定输入、输出和操作的边界值。然后,根据这些边界值设计相应的单元测试用例,覆盖各种边界情况。
4)实验问题:单元测试用例设计过程中遇到了重复劳动和低效率的情况。
解决方法:尝试利用单元测试用例模板,提前定义好单元测试用例的结构和格式。模板可以包括测试目标、测试步骤、输入数据、预期结果等内容,以减少重复工作。可以将常见的测试场景和用例模板存储在团队的知识库中,以便团队成员共享和复用,提高设计效率。也可以尝试自动化测试工具来辅助单元测试用例设计和生成,以进一步提高效率和准确性。通过团队内部的交流和协作,可以共同发现和解决单元测试用例设计中的问题,不断改进和优化测试流程,提高工作效率和质量。
5)实验问题:单元测试用例过于冗长或复杂,不利于理解和执行。
解决方法:对于复杂的测试场景,可以将单元测试用例进行拆分,以简化测试步骤和降低测试难度。同时,可以使用图形化工具或流程图来清晰地展示测试步骤和流程,提高单元测试用例的可读性和可执行性。
6)实验问题:在设计单元测试用例时遇到了测试数据的获取困难,无法构造有效的测试场景。
解决方法:通过模拟或虚拟数据生成工具生成测试数据,以满足单元测试用例的需求,确保测试数据的真实性和有效性。
7)实验问题:在执行单元测试用例时遇到了性能稳定性问题,导致测试结果不准确或不稳定。
解决方法:通过性能测试工具对函数进行性能测试,发现函数的瓶颈和性能问题,并及时采取优化措施。可以对函数进行压力测试和负载测试,以评估函数在高负载情况下的稳定性和可靠性。
8)实验问题:单元测试用例设计过程中遇到了缺乏实际经验或领域知识的挑战,无法充分覆盖所有可能的测试场景。
解决方法:通过学习和培训提升自己的测试技能和领域知识,以更好地理解函数的功能和业务流程,并设计出更全面的单元测试用例。同时,可以与团队成员进行知识共享和经验交流,共同解决测试设计中的难题。
2、实验心得体会:
(1)在实验中,我深刻认识到对需求的准确理解是测试工作的基础。在设计单元测试用例之前,必须对软件函数的功能需求有清晰的认识,包括各个功能点的具体要求和期望的输出。为了确保对需求的理解准确,我多次阅读了需求文档,并进行了讨论和沟通,以澄清任何不清楚的地方。只有确保对需求的准确理解,才能够设计出充分覆盖各种情况的单元测试用例,从而提高测试的有效性和全面性。
(2)通过此次实验我学会了不同的单元测试用例设计技巧,如等价类划分、边界值分析和错误推测等。这些技巧在设计单元测试用例时非常实用,可以帮助我发现潜在的软件缺陷并提高测试的覆盖率。例如,在设计边界值单元测试用例时,我注意到了函数在边界处的行为是否符合预期,并设计了相应的单元测试用例进行验证。在设计等价类划分单元测试用例时,我将输入数据分成有效类和无效类,并针对每个类别设计了相应的单元测试用例。通过灵活运用不同的单元测试用例设计技巧,我能够设计出更加全面和有效的单元测试用例,提高测试的质量和效率。
(3)实验不仅是一个学习的过程,也是一个不断改进的过程。在实验中,我不仅学到了很多关于软件测试和质量控制的知识和技能,还不断地探索新的方法和技巧,以提高测试工作的效率和质量。例如,在设计单元测试用例时,我尝试了不同的方法和技巧,并根据实际情况进行了调整和改进。通过持续学习和改进,我能够不断提高自己的测试技能和水平,不断优化测试过程,以应对日益复杂的软件函数和测试需求。
(4)在实验结束后,我对整个实验过程进行了反思和总结。我回顾了实验中遇到的问题和解决方案,分析了实验过程中的不足和改进空间,并提出了相应的改进建议。通过反思和总结,我深刻认识到了自己的不足之处,并下定决心在以后的学习和工作中不断改进和提高自己。我将继续保持对新知识和新技能的学习和探索,不断完善自己的测试技能,为今后的学习和工作打下更加坚实的基础。
3、实验意见与建议:
(1)增加更多的实际案例和练习机会,可以帮助我们将理论知识与实际应用相结合。通过实际案例的分析和解决,可以加深我们对软件测试和质量控制的理解,提高实践能力。这些案例和练习可以包括真实的软件函数或项目案例,让我们在实践中掌握测试方法和技巧,培养解决问题的能力。同时,可以提供实际项目中的测试场景和需求文档,让我们从实际项目中学习,提高实验的实用性和应用性
(2)增加对测试工具的培训和应用,可以帮助我们掌握常用测试工具的基本操作和功能,提高测试工作的效率和质量。同时,也可以增加对开源测试工具的介绍和应用,以提供更多选择和学习机会。安排专门的课程或实验环节,介绍常用的测试工具,如禅道、Selenium、JMeter等,并结合实际案例进行演示和操作。同时,可以鼓励我们在实验中使用测试工具进行测试任务的完成,提供实际操作的机会,加深对测试工具的理解和应用能力。
(3)提供个性化的指导和反馈,可以帮助我们更好地理解和掌握知识,解决遇到的问题。通过及时的指导和反馈,可以帮助我们更快地进步,提高实验成绩和学习效果。安排实验指导老师或助教进行一对一或小组指导,解答学生的问题,提供学习建议和反馈意见。同时,可以组织学生进行实验报告的互评和同行评议,促进学生之间的交流和学习,提高实验报告的质量和水平。
(4)鼓励我们独立思考和创新实践,可以激发我们的学习兴趣和创造力,培养我们的问题解决能力和创新意识。设置开放性的实验项目或任务,让我们自由选择研究方向和方法,进行探索和实践。同时,可以提供创新性实验项目或课程设计,鼓励学生进行创新性的实验和项目研究,培养学生的问题解决能力和创新意识。
(5)关注实验设备和环境的改进,提供良好的实验条件和环境,可以帮助我们更好地进行实验和学习,提高实验效果和体验。通过更新实验设备,配备最新的软硬件设备和工具,提高实验设备的性能和稳定性。同时,可以改善实验环境,提供舒适的学习环境和便利的实验条件,为我们的学习和实验提供良好的支持和保障。