一、简单介绍
JUnit是一个Java语言的单元测试框架。基于Xunit架构的单元测试框架的实例。
二、应用场景
JUnit在日常的工作中经常用到,比如,本文会对超时、异常、参数化、规则等方面进行举例。日常的使用大体分为两种情况:
一种最简单的方式是在方法上标注@Test注解进行测试;
另一种是需要整合Spring的配置文件进行bean的创建、数据库的连接等测试,
这两种模式的实践请参考下文。
三、详细介绍
1、Junit使用说明
1、写在test目录下
2、测试的包名和被测试的包名相同
3、测试的方法名以test开头
4、测试方法上必须使用@Test进行修饰
5、测试方法必须使用public void进行修饰,不能带任何的参数
6、测试单元中的每个方法必须可以独立测试、测试方法间不能有任何的依赖
7、测试类使用Test作为类名的后缀
8、对被测试类右键创建新的Junitclass 可提高效率(类右键-New-Junit Test Case 见图1)
图1
2、Junit运行结果说明:
图2
Runs:经单元测试的方法
Failures: 一般由单元测试使用的断言方法判断失败引起的,这 就表示,测试点发现了问题,就是说程序输出的结果和预期的不一样
Errors:是由代码异常引起的,它可以产生于测试代码本身的错误,也可以是被测试代码中的一个隐藏的bug
3、Junit的运行流程:
1、先执行@BeforeClass修饰的测试方法、
2、再执行@Before修饰的方法、
3、再执行@Test修饰的方法、
4、再执行@After修饰的方法、
5、再执行@AfterClass执行的方法。
在同一个类中@BeforeClass修饰的类和@AfterClass修饰的方法只执行一次,@Before与@After修饰的方法的执行次数由@Test修饰的方法的个数决定。
1、@BeforeClass修饰的方法会在所有方法被调用前被执行,而且该方法是静态的,所以当测试类被加载后接着就会运行它,而且在内存中它存在一份示例,它比较适合加载配置文件
2、@AfterClass所修饰的方法通常用来对资源的释放,如关闭数据库的连接
3、@Before和@After会在每个测试方法的前后各执行一次。
执行的效果如图3所示:
图3
4、Junit的常用注解:
@Test:将一个普通的方法修饰成为一个测试方法
可以在类上右键-Run With(Debugs With)-JUnit Test 对这个类内所有标注@Test的方法进行单元测试
也可以在@Test标注的方法上右键-Run With(Debugs With)-JUnit Test ,此时只会对当前方法进行单元测试
@Test(expected=XXX.class) 期望异常测试
例如:@Test(expected=ArithmeticException.class)
如果测试该方法时产生一个ArithmeticException的异常,则表示测试通过,否则测试不通过,没有达到预期值。
@Test(timeout=毫秒) 设置超时时间
若在设置的时间内方法没有执行完则测试失败。
@BeforeClass:它会在所有的方法运行前被执行,static修饰
@AfterClass:它会在所有的方法运行结束后被执行,static修饰
@Before:它会在每一个测试方法运行前被执行一次
@After:它会在每一个测试方法运行结束后被执行一次
@Ignore:所修饰的测试方法会被测试运行器所忽略
在类上执行Junit测试时,标注@Ignore的方法将不再执行
@RunWith:可以更改测试运行器
JUnit所有的测试方法都是由测试运行器负责执行,
默认的测试运行器:BlockJUnit4ClassRunner
例如:@RunWith(Suite.class) 其作用是使用JUnit执行一个测试套件。
@RunWith(SpringJUnit4ClassRunner.class),让测试运行于Spring测试环境
@RunWith(Parameterized.class)参数化测试:对多组数据同时测试
@Parameters:生成静态参数用于参数化测试
5、Junit的参数化测试
用多组参数对同一个方法进行批量的单元测试,例如对日期、数值类型的计算时,一定要注意几个重要节点的测试。
参数化测试的步骤:
1、更改默认的测试运行器为@RunWith(Parameterized.class)
2、声明变量来存放预期值和结果值
3、声明一个返回值为Collection的公共静态方法,并使用@Parameters进行修饰
4、为测试类声明一个带有的公共构造函数,并在其中为之声明变量赋值
例如:
@RunWith(Parameterized.class)
public class RunWithParameterTest {
int expected = 0;
int input1 = 0;
int input2 = 0;
@Parameters
public static Collection<Object[]> t() {
return Arrays.asList(new Object[][] { { 3, 1, 2 }, { 4, 3, 2 },{5,1,4} })
}
public RunWithParameterTest(int expected, int input1, int input2) {
this.expected = expected;
this.input1 = input1;
this.input2 = input2;
}
@Test
public final void parameterTest() {
assertEquals(expected, new JunitTest2().add(input1, input2));
}
6、Junit4的测试套件(@RunWith(Suite.class))
项目中存在多个测试类,一个一个运行比较麻烦,可以通过测试套件批量运行
测试套件的步骤:
1、测试套件就是组织测试类一起运行的
2、写一个作为测试套件的入口类,这个类里不包含其他的方法
3、更改测试运行器Suite.class 将要测试类作为数组传入到Suit.SuiteClasses({})
例如:
@RunWith(Suite.class)
@Suite.SuiteClasses({ JunitTest2Test.class, JunitAnotationTest.class })
public class RunWithTest {
}
7、Junit与Spring的整合。
一般情况需要配置三个注解就可以了。
@RunWith(value = SpringJUnit4ClassRunner.class)
说明: 在使用所有注解前必须使用,让测试运行于Spring测试环境
@WebAppConfiguration
说明:由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上此注解
@ContextConfiguration(locations = { "classpath*:applicationContext.xml",
"classpath*:applicationContext-redis.xml",
"classpath*:applicationContext-db.xml",
"classpath*:applicationContext-db-jpa.xml" })
说明:@ContextConfiguration 用来指定加载的Spring配置文件的位置,会加载默认配置文件,
例如:
@RunWith(value = SpringJUnit4ClassRunner.class) // 在使用所有注释前必须使用,让测试运行于Spring测试环境
@WebAppConfiguration //由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration。
//【@ContextConfiguration 用来指定加载的Spring配置文件的位置,会加载默认配置文件,
@ContextConfiguration(locations = { "classpath*:applicationContext.xml",
"classpath*:applicationContext-redis.xml",
"classpath*:applicationContext-db.xml",
"classpath*:applicationContext-db-jpa.xml" })
public class SpringJunitTest {
@Autowired
private RedisService redisService;
@Test
public void springTest() {
UsersEntity userdentity = redisService.getUserInfo(1);
System.out.println(userdentity.toString());
}
8、Junit4常用的断言函数:
AssertEquals:断言两个结果相等;
AssertArrayEquals:断言两个数组相等;
AssertNotEquals:断言两个结果不相等;
AssertSame:判断两个对象是否为同一个,不同于equals这里是使用“==”判断;
AssertTrue:断言结果为真;
AssertFalse:断言结果为假;
AssertNull:断言结果为空;
AssertNotNull:断言结果不为空;
AssertThat:使用Matcher做自定义的校验;
例如:
@Test
public void test() {
assertEquals(6, new JunitTest1().add(3, 3));
}
若相等,则测试通过,若不相等则failur
四、Junit实践
引入依赖:
1、@BeforeClass、@AfterClass、@Bfore、@After、@Test的综合测试示例:
public class JunitTest2Test {
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("@BeforeClass 测试...");
System.out.println();
}
/**
* @throws java.lang.Exception
*/
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("@AfterClass 测试...");
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
System.out.println("@Before 测试...");
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
System.out.println("@After 测试....");
System.out.println();
}
@Test
public void testAdd() {
System.out.println("testAdd 测试...");
assertEquals(6, new JunitTest2().add(3, 3));
}
@Test
public void testSubtrc() {
System.out.println("testSubtrc 测试...");
assertEquals(0, new JunitTest2().subtrc(3, 3));
}
}
执行结果如图4所示:
图4
2、@Ignore测试示例:
@Ignore
@Test
public void ignoreTest() {
System.out.println("Ignore 测试...");
}
此单元测试方法会跳过
3、@Test(timeout = 1000)//timeout属性测试
@Test(timeout = 1000)//限制运行的时间
public void timeoutTest() {
while (true) {
System.out.println("123");
}
}
此方法会超时报错。
4、@Test(expected=xxx.class)//expected属性测试
@Test(expected=ArithmeticException.class)//拦截各种异常
public void divisionTest() {
System.out.println("expected 属性测试");
assertEquals(3, new JunitTest1().division(3, 0));
}
此方法异常拦截,正常运行,division是一个除运算。
5、Junit的参数化测试、Junit的测试套件、Junit与Spring的整合等的测试示例见上面的详细介绍,或者见下面的源码。
五、源码
源码下载地址:
https://github.com/jiudaoliu/JunitDemo.git
更多java技术相关的文章,敬请关注公众号:九刀流