單元測試框架TestNG、Mockito、Unitils-Spring及示例
阿新 • • 發佈:2018-12-04
一. 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>