![cover](https://img-blog.csdnimg.cn/direct/7160caa7c99647aca8bacfd5a533dafa.png)
JUnit单元测试及相关案例实验
JUnit单元测试JUnitht是开源测试框架体系xUnit的一个实例可以方便地组织和运行Java程序的单元测试。JUnit的源代码是公开的,并具有很强的扩展性,可以进行二次开发,方便地对JUnit进行扩展。JUnit具有如下特点。可以使测试代码与产品代码分开,这更有利于代码的打包发布和测试代码的管理。针对某一个类写的测试代码,以较少的改动便可以应用到另一个类的测试JUnit提供。
目录
JUnit单元测试
JUnit(http://www.junit.org)是开源测试框架体系xUnit的一个实例,可以方便地组织和运行Java程序的单元测试。JUnit的源代码是公开的,并具有很强的扩展性,可以进行二次开发,方便地对JUnit进行扩展。JUnit具有如下特点。
- 可以使测试代码与产品代码分开,这更有利于代码的打包发布和测试代码的管理。
- 针对某一个类写的测试代码,以较少的改动便可以应用到另一个类的测试,JUnit提供 了一个编写测试类的框架,使测试代码的编写更加方便。
易于集成到程序构建的过程中,JUnit和Ant的结合还可以实施增量开发。
JUnit 一共有 6 个包,包括 junit.awtui、junit.swingui、junit.textui、junit.extensions、junit.framework、junit.runner,前3个包中包含了JUnit运行时的入口程序以及运行结果显示界面,junit.extensions是扩展包,而junit.framework、junit.runner是核心包,分别负责整个测试对象的构建、测试驱动和运行。
JUnit有7个核心类,分别是TestSuite、TestCase、TestResult、TestRunner、Test、TestListener接口和Assert(断言)类,其关系如图所示。
![](https://img-blog.csdnimg.cn/direct/7160caa7c99647aca8bacfd5a533dafa.png)
Assert类用来验证条件是否成立,当条件成立时,assert方法保持沉默(测试通过),若条件不成立时就抛出异常。该类所提供的核心方法,主要有assertTrue、assertFalse、 assertEquals、assertNotNull、assertNull、assertSame和assertNotSame等。
Test接口是单独的测试用例、聚合的测试模式以及测试扩展的共同接口,用来实施测试和收集测试的结果,Test接口采用了Composite设计模式。
TestCase 抽象类用来定义测试中的固定方法,TestCase 是 Test 接口的抽象实现,由于TestCase是一个抽象类,因此不能被实例化,只能被继承。其构造方法可以根据输入的测试名称来创建一个测试用例,设定测试名称的目的在于方便测试失败时查找失败的测
试用例。
TestSuite是由几个TestCase或其他的TestSuite构成的,从而构成一个树形结构的测试 任务。每个测试任务都由一个或若干个TestSuite来构成。被加入到TestSuite中的测试 在一个线程上依次被执行。
TestResult负责收集TestCase所执行的结果,它将结果分类,分为客户可预测的错误和 没有预测的错误,它还将测试结果转发到TestListener处理。
TestRunner是客户对象调用的起点,负责跟踪整个测试过程,能够显示测试结果,并且 报告测试的进度。
TestListenter包含4种方法——addError()、adaddFailuer()、startTest()和endTest()。它是 对测试结果的处理和对测试驱动过程的工作特征进行提取。
用JUnit进行单元测试
下面介绍一下如何在IDEA 2020.1.2中用JUnit工具完成单元测试。
IDEA中自带JUnit的jar包(hamcrest-core-1.3.jar,junit.jar,junit-4.12.jar):位于安装目录下的lib文件内。即:IntelliJ IDEA 2020.1.2\lib
IDEA自带一个JUnit插件, 该插件可以运行JUnit测试文件,但无法自动生成JUnit测试代码. 如果需要自动生成测试代码,需要安装JUnitGenerator V2.0插件。
安装方法:File-->settings-->Plguins-->Browse repositories-->输入 JUnit-->选择 JUnit Generator V2.0安装,安装好后重启 IDEA,即可使用。
PS: IDEA自带的JUnit插件和JUnitGeneratorV2.0插件都要勾选上,若只勾选JUnit可能导致无法自动生成测试文件,若只勾选JUnitGenerator V2.0可能导致生成的测试文件无法运行。
修改配置
1.通过模版生成的测试代码与java类在同一个目录下,与maven项目标准测试目录不匹配。
修改方法:
${SOURCEPATH}/test/${PACKAGE}/${FILENAME}
修改为
${SOURCEPATH}/../test/java/${PACKAGE}/${FILENAME}
有时候会出现一个提示框,提示选择(general/merge/exixt),选择 general 就行。
${SOURCEPATH}原类的路径,就是你自己写的类;${PACKAGE}原类的包名,java包命名规范就是按照包名一级一级创建的文件夹;${filename}测试类的类名。
2.修改 Junit4 选项卡中包的申明,把默认的 test 前缀去掉。
3.生成的测试文件@since位置Date可能存在乱码,可配置JUnit模板更改日期格式,不影响程序可直接忽略。
修改方法:
第40行:
@since <pre>$date</pre>
修改为
@since <pre>$today</pre>
举例1
下面就让我们从“Helloworld”开始第一个单元测试。新建一个项目“JunitTest”,然后,创建一个Helloworld类,其Java的源代码如下所示。
public class Helloworld{
public String say(){
return("Hello World!");
}
}
在Helloworld类代码编辑框内单击鼠标右键,在弹出的菜单中选择Generate(对应快捷键为 Alt+Insert)-> Junit Test -> Junit 4,这时 IDEA 会自动生成一个 test 目录并生成HelloworldTest类。将其中的testSay()方法修改为如下代码:
public final void testSay()
{
Helloworld hi = new Helloworld();
assertEquals("Hello World!",
hi.say());
}
在 IDEA中把产品代码放在src目录中,把测试代码放在test目录中,在命令行中要设置 SOURCEPATH环境变量,在 IDEA中可以右键单击 test目录,在弹出的菜单中选择 Mark Directory as->Test Sources Root即可(这时test文件夹图标会变绿)。
鼠标右键点击HelloworldTest类,然后选择Run’HelloworldTest’,运行测试类,即可查看测试结果。
举例2
测试一个四则运算程序,源程序如下所示。
public class Calculator
{
public int add(int x, int y)
{ //加法
return x + y;
}
public int sub(int x, int y)
{ //减法
return x - y;
}
public int mul(int x, int y)
{ //乘法
return x * y;
}
public int div(int x, int y)
{ //除法
return x / y;
}
public int div2(int x, int y)
{ //除法 做了异常判断
try
{
int z = x / y;
}
catch(Exception e)
{
e.printStackTrace();
}
return x / y;
}
}
按照之前的步骤生成CalculatorTest 类,并修改其中的testAdd()、testSub()、testMul()、testDiv()、testDiv2()方法,如下所示:
public void testAdd() throws Exception
{
if(calculator.add(8, 2) == 10)
{
System.out.println("Test passed!");
}
else
{
System.out.println("Test failed!");
}
}
public void testSub() throws Exception
{
if(calculator.sub(8, 2) == 6)
{
System.out.println("Test passed!");
}
else
{
System.out.println("Test failed!");
}
}
public void testMul() throws Exception
{
if(calculator.mul(8, 2) == 16)
{
System.out.println("Test passed!");
}
else
{
System.out.println("Test failed!");
}
}
public void testDiv() throws Exception
{
if(calculator.div(8, 2) == 4)
{
System.out.println("Test passed!");
}
else
{
System.out.println("Test failed!");
}
}@
Rule
public ExpectedException exception = ExpectedException.none();@
Test()
public void testDiv2() throws Exception
{
exception.expect(Exception.class);
exception.expectMessage("除数不合法");
calculator.div2(8, 3);
}
鼠标右键点击CalculatorTest类,然后选择Run’CalculatorTest with coverage’,运行测试类,并可查看测试覆盖率。
实验内容
使用JUnit工具,针对下列代码中的BankAccount类编写对应的测试类,以完成单元测试,最终提交测试代码和测试结果。
public class BankAccount
{
String AccountNumber;
String AccountName;
String ID;
String Password;
double TotalMoney;
public BankAccount(String AccountNumber, String AccountName, String ID, String Password)
{
thisAccountNumber = AccountNumber;
thisAccountName = AccountName;
this.ID = ID;
thisPassword = Password;
}
public void Balance(String AccountNumber)
{
System.out.println("PLEASE FIND YOUR BALANCE INFORMATION");
Systemout.println("Account name:" + AccountName);
System.out.println("Account number:" + AccountNumber);
System.out.println("Your balance:" + TotalMoney);
}
public void Deposit(double AddMoney)
{
{
try
{
if(AddMoney < 0) throw new RuntimeException();
this.TotalMoney += AddMoney;
}
catch(RuntimeException except)
{
Systemout.println("Failed to deposite, money should be larger than 0");
}
System.outprintln("Deposited money succeeded, the total money is:" + TotalMoney);
}
}
public void Withdraw(double GetMoney)
{
try
{
if {
(GetMoney > this.TotalMoney) throw new RuntimeException();
this.TotalMoney -= GetMoney;
System.out.println("You have withdrawed money:" + GetMoney);
}
catch(RuntimeException except)
{
System.out.println("Error! you don't have enough balance");
}
}
}
实验结果(个人)
案例一(HelloWorld类测试)
案例二(Calculate类测试)
测试覆盖率:
测试BankAccount类
测试类BankAccountTest代码如下:
package com.xzp.util;
import org.junit.Rule;
import org.junit.Test;
import org.junit.Assert.*;
import org.junit.Before;
import org.junit.After;
import org.junit.rules.ExpectedException;
/**
* BankAccount Tester.
*
* @author GiperHsiue
* @since <pre>11月 25, 2022</pre>
* @version 1.0
*/
public class BankAccountTest {
BankAccount account1;
@Before
public void before() throws Exception {
account1 = new BankAccount("8008", "xzp", "1",
"1");
account1.TotalMoney = 200;
System.out.println("Before...初始化了账户余额:200");
}
@After
public void after() throws Exception {
System.out.println("After\n");
}
/**
*
* Method: Balance(String AccountNumber)
*
*/
@Test
public void testBalance() throws Exception {
//TODO: Test goes here...
}
/**
*
* Method: Deposit(double AddMoney)
*
*/
@Test
public void testDeposit() throws Exception {
//TODO: Test goes here...
double tmp = account1.TotalMoney;
double inp = 1000;
tmp += inp;
account1.Deposit(inp);
org.junit.Assert.assertEquals(tmp, account1.TotalMoney, 0);
}
/**
*
* Method: Withdraw(double GetMoney)
*
*/
@Test
public void testWithdraw() throws Exception {
//TODO: Test goes here...
double tmp = account1.TotalMoney;
double inp = 100;
tmp -= inp;
account1.Withdraw(inp);
org.junit.Assert.assertEquals(tmp, account1.TotalMoney, 0);
}
@Rule
public ExpectedException expectedDes = ExpectedException.none();
@Test
public void testDepositThrow(){
expectedDes.expect(RuntimeException.class);
expectedDes.expectMessage("Failed to deposite, money should be larger than 0");
account1.Deposit(-100);
}
@Rule
public ExpectedException expectedWith = ExpectedException.none();
@Test
public void testWithdrawThrow(){
expectedWith.expect(RuntimeException.class);
expectedWith.expectMessage("Error! you don't have enough balance");
account1.Withdraw(2000);
}
}
运行如下:
测试覆盖率:
![Logo](https://devpress.csdnimg.cn/79de2bf0b7994defa4242ef90d5513fa.jpg)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)