单元测试框架TestNG、Mockito、Unitils-Spring及示例
程序员文章站
2022-04-26 09:40:45
...
一. TestNG 对Junit的扩展可通过xml脚本同时运行多个case
TestNG运行时将经过一下几个阶段:
1. 类级初始化资源处理 @BeforeClass注解标记
2. 方法级别初始化资源处理 @BeforeMethod
3. 执行测试用例中的方法 @Test
4. 方法级别的销毁 @AfterMethod
5. 类级别的销毁 @AfterClass
如果定义了多个初始化方法,先执行定义在最后面的,而销毁方法先执行定义在最前面的。
如果定义多个@Test的用例,会为每个@Test方法生成一个测试用例实例分别运行。
@BeforeClas @AfterClass在一个测试用例实例中只运行一次。
测试方法: 通过@Test标注方法执行一个测试逻辑,然后通过Assert进行断言。
详细实例请见:com.test.TestNGLearn
二. Mockito
Mockito只适用于对Service层的方法进行单元测试
Mockito可以mock某些类和方法的执行,设定某些期望的行为和返回值
常用来测试判定逻辑等,通过mock避免执行某些依赖的逻辑
Mockito + Assert 可以方便的测试服务类的逻辑结构。
详细实例请见:com.test.MockitoLearn
三. Unitils
专用于测试框架整合, 通过配置文件开启模块功能。unitils定义了Module接口,通过实现这个接口整合其他框架,同时也可以自定义。
1. ReflectionAssert反射断言 详细实例见: com.test.UnitilsLearn
2. 集成Spring 详细实例见:com.test.UnitilsSpring
3. 集成Hibernate
4. 集成DBUtil
5. 对web层测试
TestNG示例:
package com.test;
import org.testng.annotations.*;
// 用于指定类属于的分组
// @Test(groups = {"group1"})
public class TestNGLearn {
@BeforeClass
public static void init(){
System.out.println("类初始化");
}
@AfterClass
public static void destroy(){
System.out.println("类销毁");
}
@BeforeMethod
public void initMethod(){
System.out.println("用例执行初始化");
}
@Test
public void testTestNG(){
System.out.println("一个简单的测试");
}
// 开启异常测试,如果没有抛出指定的异常则测试失败。
@Test(enabled = true , expectedExceptions = RuntimeException.class)
public void testException(){
throw new RuntimeException();
}
// 如果在timeOut指定的毫秒时间内未完成则测试失败
@Test(enabled = true, timeOut = 2000)
public void testTimeOut() throws InterruptedException{
Thread.sleep(2000);
}
// 参数化测试,直接提供批量的测试参数,不必为每个参数写测试用例
@DataProvider(name = "testParam")
public static Object[][] getParameters(){
String [][] params = {{"第一组第一个参数","第一组第二个参数"},{"第二组第一个参数","第二组第二个参数"}};
return params;
}
// 通过一个二维数组,指定多组参数,每组可指定多个参数。
@Test(dataProvider = "testParam")
public void testBatchParam(String first , String second){
System.out.println(first + " " +second);
}
// 分组测试, 每个测试方法单独生成实例,并都执行@BeforeMethod,而@BeforeClass之执行一次
@Test(groups = {"group1"})
public void testGroup2(){
System.out.println("分组测试 group1分组的第1个测试用例");
}
@Test(groups = {"group1","group2"})
public void testGroup1_1(){
System.out.println("分组测试 group2分组的第1个测试用例");
}
@Test(groups = {"group2"})
public void testGroup1_2(){
System.out.println("分组测试 group2分组的第2个测试用例");
}
// 依赖测试
@Test
public void testDepond(){
System.out.println("这是一个被依赖的方法");
}
@Test(dependsOnMethods = "testDepond")
public void testDepond2(){
System.out.println("前面一个方法执行成功,我才执行");
}
@AfterMethod
public void destroyMethod(){
System.out.println("用例执行收尾");
}
}
TestNG脚本方式运行: 直接右键这个xml文件运行
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<!--配置只要指定某个包,某个类,某个方法,某个组即可运行-->
<!--定义一个测试套件 指定脚本名称以进行套件区分-->
<suite name="test_suite_1">
<!--定义一个测试用例,suite脚本会运行每个测试用例-->
<test name="group1_test" >
<!--分组测试-->
<groups>
<!--群组: 将注解指定的分组,再次进行组合-->
<define name="all">
<include name="group1"/>
<include name="gourp2"/>
</define>
<!--指定运行的组和不运行的组-->
<run>
<include name = "group2" />
</run>
</groups>
<!--选择一个包中的全部@Test方法-->
<packages>
<package name = "com.test">
</package>
</packages>
</test>
<!--第二个测试用例-->
<test name="group2_test">
<!--运行指定某个类中的指定方法-->
<classes>
<class name="com.test.TestNGLearn">
<methods>
<include name="testBatchParam"/>
</methods>
</class>
</classes>
</test>
</suite>
Mokito示例:
package com.test;
import com.learn.aop.business.SayHello;
import com.learn.aop.business.SayHi;
import com.learn.mvc.domains.User;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.mockito.Mockito.*;
/**
* mokito只适用于对Service层的方法进行单元测试
* mokito可以mock某些类和方法的执行,设定某些期望的行为和返回值
* 常用来测试判定逻辑等,通过mock避免执行某些依赖的逻辑
*
* Mockito + Assert 可以方便的测试服务类的逻辑结构。
*/
public class MockitoLearn {
private static User user;
// 注解mock
@Mock
SayHi sayHi;
private SayHello sayHello;
@BeforeClass
public void intiClass(){
// 开启注解
MockitoAnnotations.initMocks(this);
}
@BeforeMethod
public void initUser(){
User user =new User();
user.setId(3);
user.setAge(18);
user.setName("asdfe");
user.setSex("female");
}
// 第一种mock方法
@Test
public void testMokito(){
// 调用方法mock产生一个虚拟的服务类
sayHello=mock(SayHello.class);
User user=new User();
doReturn(user).when(sayHello.myUser());
Assert.assertNotNull(user);
}
// 第二中mock方法
@Test
public void testMokito2(){
when(sayHi.getUser()).thenReturn(user);
User user = sayHi.getUser();
Assert.assertNotNull(user);
System.out.println(user.getName());
}
// mockito的交互验证。
// mockito能记录某个方法的执行次数。
@Test
public void testMockito3(){
// 注解生成的sayHi mock类
when(sayHi.getUser()).thenReturn(user);
// 代码生成的sayHello mock类
sayHello=mock(SayHello.class);
// 验证其是否执行
verify(sayHi).getUser();
// 验证某个类某个方法的执行次数
verify(sayHi,atLeast(1)).getUser();
verify(sayHello,atLeastOnce()).myUser();
verify(sayHello,atMost(1)).myUser();
}
}
Unitils 反射断言
package com.test;
import com.learn.mvc.domains.User;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.unitils.reflectionassert.ReflectionAssert;
import org.unitils.reflectionassert.ReflectionComparatorMode;
// 测试反射断言
public class UnitilsLearn {
private static User user1;
private static User user2;
private static User user3;
@BeforeMethod
public void initUser() {
user1 = new User();
user1.setName("vvvasd");
user2 = new User();
user3 = new User();
}
// 反射断言,判断两个实例是否相等,此处应该不相等,所以测试不通过。
@Test
public void testReflection() {
ReflectionAssert.assertReflectionEquals(user1, user3);
}
// 反射断言,判断两个实例是否相等
@Test
public void testReflection2() {
ReflectionAssert.assertReflectionEquals(user3, user2);
}
// 集合的比较 三种类型: 忽略顺序,忽略默认值,判断是否有值
@Test
public void testReflection3() {
Integer orderList1[] = new Integer[]{1, 2, 3};
Integer orderList2[] = new Integer[]{3, 2, 1};
// 忽略顺序
ReflectionAssert.assertReflectionEquals(orderList1,orderList1, ReflectionComparatorMode.LENIENT_ORDER);
// 忽略默认值
ReflectionAssert.assertReflectionEquals(orderList1,orderList1, ReflectionComparatorMode.IGNORE_DEFAULTS);
// 对日期类型只判断是否有值
ReflectionAssert.assertReflectionEquals(orderList1,orderList1, ReflectionComparatorMode.LENIENT_DATES);
}
// 断言一个POJO类中的属性是否为某个值
@Test
public void testPropertyEqual(){
User user =new User();
user.setName("hello");
// Lenient模式忽略顺序和默认值。
ReflectionAssert.assertPropertyLenientEquals("name","hello",user);
}
}
Unitils 整合spring 注意:unitils默认的启动配置中,springModule必须在databaseModule之后启动,所以如果没有配置,database数据源将导致测试运行失败。可以自定义一个unitils.property文件配置启动方式
自定义配置文件如下: 直接复制了默认的配置文件:修改
unitils.module.spring.className=org.unitils.spring.SpringModule
unitils.module.spring.runAfter=database
unitils.module.spring.enabled=true
对于unitils.module.spring.runAfter属性,将database去掉变为:unitils.module.spring.runAfter=
unitils.modules=database,dbunit,hibernate,mock,easymock,inject,spring,jpa,io
#### Unitils core configuration ###
# For each module, the implementation class is listed in unitils.module.<modulename>.className, the sequence of the
# execution of their code is influenced by unitils.module.<modulename>.runAfter. Disabling a module can be performed by
# setting unitils.module.<modulename>.enabled to false.
unitils.module.database.className=org.unitils.database.DatabaseModule
unitils.module.database.runAfter=
unitils.module.database.enabled=false
unitils.module.hibernate.className=org.unitils.orm.hibernate.HibernateModule
unitils.module.hibernate.runAfter=
unitils.module.hibernate.enabled=false
unitils.module.dbunit.className=org.unitils.dbunit.DbUnitModule
unitils.module.dbunit.runAfter=
unitils.module.dbunit.enabled=false
unitils.module.mock.className=org.unitils.mock.MockModule
unitils.module.mock.runAfter=
unitils.module.mock.enabled=false
unitils.module.easymock.className=org.unitils.easymock.EasyMockModule
unitils.module.easymock.runAfter=
unitils.module.easymock.enabled=false
unitils.module.inject.className=org.unitils.inject.InjectModule
unitils.module.inject.runAfter=
unitils.module.inject.enabled=false
unitils.module.spring.className=org.unitils.spring.SpringModule
unitils.module.spring.runAfter=
unitils.module.spring.enabled=true
unitils.module.jpa.className=org.unitils.orm.jpa.JpaModule
unitils.module.jpa.runAfter=
unitils.module.jpa.enabled=false
unitils.module.io.className=org.unitils.io.IOModule
unitils.module.io.runAfter=
unitils.module.io.enabled=false
package com.test;
import com.learn.aop.business.SayHello;
import org.junit.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.unitils.UnitilsTestNG;
import org.unitils.spring.annotation.SpringApplicationContext;
import org.unitils.spring.annotation.SpringBean;
import org.unitils.spring.annotation.SpringBeanByType;
/**
* 注意一定要集成UnitilsTestNG类
* unitils 启动会开启springModule然后初始化spring容器。
* Unitils TestNG一定要一个数据源才能启动
*/
@SpringApplicationContext({"spring-servlet.xml"})
public class UnitilsSpring extends UnitilsTestNG {
@SpringBean("sayHelloTarget")
public SayHello sayHello;
// @SpringBeanByName
// public SayHello sayHello2;
@SpringBeanByType
public SayHello sayHello3;
@BeforeMethod
public void before() {
System.out.println("开始准备");
}
@AfterMethod
public void after() {
System.out.println("运行结束");
}
// 测试手动启动
// @Test
// public void testSpring() {
// ApplicationContext context = new ClassPathXmlApplicationContext("spring-test.xml");
// sayHello2 = (SayHello) context.getBean("sayHello");
// Assert.assertNotNull(sayHello2);
// }
// 测试注解启动
@Test
public void testSpring2() {
sayHello.sayHello();
Assert.assertNotNull(sayHello);
}
// 测试注解启动
@Test
public void testSpring3() {
sayHello3.sayHello();
Assert.assertNotNull(sayHello3);
}
}
最后附上导入的包
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.21.0</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.unitils/unitils-core -->
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-core</artifactId>
<version>3.4.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.unitils/unitils-spring -->
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-spring</artifactId>
<version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.unitils/unitils-testng -->
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-testng</artifactId>
<version>3.3</version>
</dependency>
上一篇: springboot单元测试
下一篇: 如何用golang编写单元测试用例