引言
這篇文章将幫你了解如下内容:
單元測試架構如何在自動化測試中應用;
junit4如何上手;
junit4的進階功能有哪些;
junit4中用例并發和用例失敗重試的方案;
單元測試
單元測試(Unit Testing),是一種軟體測試方法,通過這種測試方法測試各個源代碼單元,一個或者多個子產品的集合,使用程式來測試程式,來保證它們的可用性。一般來說單元測試由開發人員自己來執行。單元測試是由開發人員編寫的一段代碼,用于檢查被測試代碼的一個小的、明确的功能是否正确。由于近些年來ui自動化測試和接口測試的流行,單元測試也被引入到自動化測試領域,我們通常編寫的自動化測試腳本都是基于單元測試架構。不同的語言有其對應的單元測試架構。例如:Java的主流單元測試架構包括:Junit4\TestNG;Python的主流單元測試架構包括:unittest\pytest等等。
Junit概念
Junit是一個可編寫重複測試的簡單架構,是基于Xunit架構的單元測試架構的執行個體。Junit4最大的改進是大量使用注解(中繼資料),很多實際執行 過程都在Junit的背景做完了,而且寫test case 的類不需要繼承TestCase,隻需要在所要做test case的方法前加@Test 注解即可。Junit被預設的作為Eclipse插件,內建到Eclipse中。
新特性:
(1)、使用junit4.x版本進行單元測試時,不用測試類繼承TestCase父類
(2)、junit4.x版本,引用了注解的方式,進行單元測試;
Junit4環境搭建
Java 工程中add Library

選擇Junit4 點選Finish按鈕
Junit4的常用注解
junit4.x版本我們常用的注解:
A、@Before 注解:與junit3.x中的setUp()方法功能一樣,在每個測試方法之前執行;
B、@After 注解:與junit3.x中的tearDown()方法功能一樣,在每個測試方法之後執行;
C、@BeforeClass 注解:在所有方法執行之前執行;
D、@AfterClass 注解:在所有方法執行之後執行;
JUnit4的用例執行順序是:@BeforeClass> @Before> @Test1> @After>@Before> @Test2> @After….. @AfterClass
E、@Test(timeout = xxx) 注解:設定目前測試方法在一定時間内運作完,否則傳回錯誤;
F、@Test(expected =Exception.class) 注解:設定被測試的方法是否有異常抛出。抛出異常類型為:Exception.class;
G、@Ignore 注解:注釋掉一個測試方法或一個類,被注釋的方法或類,不會被執行。
H、@RunWith注解:指定用例的運作Runner,是用來修飾類的,而不是用來修飾函數的。隻要對一個類指定了 Runner ,那麼這個類中的所有函數都被這個 Runner 來調用。
assertThat
JUnit 4.4 結合 Hamcrest 提供了一個全新的斷言文法——assertThat。assertThat 使用了Hamcrest 的Matcher 比對符,使用者可以使用比對符規定的比對準則精确的指定一些想設定滿足的條件,具有很強的易讀性,而且使用起來更加靈活。使用assertThat 需要導入:
import static org.hamcrest.CoreMatchers.*;
assertThat的主要功能如下:
一般比對符
1、assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );
注釋: allOf比對符表明如果接下來的所有條件必須都成立測試才通過,相當于“與”(&&)
2、assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
注釋:anyOf比對符表明如果接下來的所有條件隻要有一個成立則測試通過,相當于“或”(||)
3、assertThat(testedNumber, anything() );
注釋:anything比對符表明無論什麼條件,永遠為true
4、assertThat(testedString, is( "developerWorks" ) );
注釋: is比對符表明如果前面待測的object等于後面給出的object,則測試通過
5、assertThat(testedString, not( "developerWorks" ) );
注釋:not比對符和is比對符正好相反,表明如果前面待測的object不等于後面給出的object,則測試通過
字元串相關比對符
1、assertThat( testedString,containsString( "developerWorks" ) );
注釋:containsString比對符表明如果測試的字元串testedString包含子字元串"developerWorks"則測試通過
2、assertThat(testedString, endsWith ( "developerWorks" ) );
注釋:endsWith比對符表明如果測試的字元串testedString以子字元串"developerWorks"結尾則測試通過
3、assertThat(testedString, startsWith ( "developerWorks" ) );
注釋:startsWith比對符表明如果測試的字元串testedString以子字元串"developerWorks"開始則測試通過
4、assertThat(testedValue, equalTo( expectedValue ) );
注釋: equalTo比對符表明如果測試的testedValue等于expectedValue則測試通過,equalTo可以測試數值之間,字元串之間和對象之間是否相等,相當于Object的equals方法
5、assertThat(testedString, equalToIgnoringCase( "developerWorks" ) );
注釋:equalToIgnoringCase比對符表明如果測試的字元串testedString在忽略大小寫的情況下等于"developerWorks"則測試通過
6、assertThat(testedString, equalToIgnoringWhiteSpace( "developerWorks" ) );
注釋:equalToIgnoringWhiteSpace比對符表明如果測試的字元串testedString在忽略頭尾的任意個空格的情況下等于"developerWorks"則測試通過,注意:字元串中的空格不能被忽略
數值相關比對符
1、assertThat(testedDouble, closeTo( 20.0, 0.5 ) );
注釋:closeTo比對符表明如果所測試的浮點型數testedDouble在20.0±0.5範圍之内則測試通過
2、assertThat(testedNumber, greaterThan(16.0) );
注釋:greaterThan比對符表明如果所測試的數值testedNumber大于16.0則測試通過
3、assertThat(testedNumber, lessThan (16.0) );
注釋:lessThan比對符表明如果所測試的數值testedNumber小于16.0則測試通過
4、assertThat(testedNumber, greaterThanOrEqualTo (16.0) );
注釋: greaterThanOrEqualTo比對符表明如果所測試的數值testedNumber大于等于16.0則測試通過
5、assertThat(testedNumber, lessThanOrEqualTo (16.0) );
注釋:lessThanOrEqualTo比對符表明如果所測試的數值testedNumber小于等于16.0則測試通過
collection相關比對符
1、assertThat( mapObject,hasEntry( "key", "value" ) );
注釋:hasEntry比對符表明如果測試的Map對象mapObject含有一個鍵值為"key"對應元素值為"value"的Entry項則測試通過
2、assertThat(iterableObject, hasItem ( "element" ) );
注釋:hasItem比對符表明如果測試的疊代對象iterableObject含有元素“element”項則測試通過
3、assertThat( mapObject,hasKey ( "key" ) );
注釋: hasKey比對符表明如果測試的Map對象mapObject含有鍵值“key”則測試通過
4、assertThat( mapObject,hasValue ( "key" ) );
注釋:hasValue比對符表明如果測試的Map對象mapObject含有元素值“value”則測試通過
Junit4應用
建立一個junit4用例
New>選則JUnit Test Case
選擇New Junit4 test,點選Finish即完成了一個Junit4 用例的建立工作
執行個體代碼
public class Junit4Demo {
@BeforeClass
public static void setUpBeforeClass()throws Exception {
}
@AfterClass
public static void tearDownAfterClass()throws Exception {
}
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void EmptyCollection() {
Collection collection =newArrayList();
assertTrue(collection.isEmpty());
}
@Test
public void MyString() {
assertEquals("Test",newString("Test"));
}
@Test
public void MyNull() {
assertEquals(null,"abc");
}
}
執行多個測試用例
執行多個測試用例的意義是将多個測試用例通過suite管理起來。
New一個Test Suite,點選Next
可以自定義需要執行的測試用例
點選Finish,生成代碼如下:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({Junit4Demo.class, Junit4Demo2.class })
public class AllTests {
}
使用@Rule擴充Junit4
Rule是JUnit4中的新特性,它讓我們可以擴充JUnit的功能,靈活地改變測試方法的行為。JUnit4中包含兩個注解@Rule和@ClassRule用于修飾Field或傳回Rule的 Method,Rule是一組實作了TestRule接口的共享類,提供了驗證、監視TestCase和外部資源管理等能力。JUnit提供了以下幾個Rule實作,必要時也可以自己實作Rule。
Verifier: 驗證測試執行結果的正确性。
ErrorCollector: 收集測試方法中出現的錯誤資訊,測試不會中斷,如果有錯誤發生測試結束後會标記失敗。
ExpectedException: 提供靈活的異常驗證功能。
Timeout: 用于測試逾時的Rule。
ExternalResource: 外部資源管理。
TemporaryFolder: 在JUnit的測試執行前後,建立和删除新的臨時目錄。
TestWatcher: 監視測試方法生命周期的各個階段。
TestName: 在測試方法執行過程中提供擷取測試名字的能力。
簡單的說就是提供了測試用例執行過程中一些通用功能的共享的能力,使我們不必重複編寫一些功能類似的代碼。JUnit用于标注Rule的注解包括@Rule和@ClassRule,差別在于作用域不同@Rule的作用域是測試方法,@ClassRule則是測試Class。
自定義Rule執行個體:
自定義一個rule, 實作循環執行一個方法,代碼如下:
import java.util.Arrays;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
class RepeatableRule implements MethodRule{
int times=1;
String[] testMethods = null;
RepeatableRule(int times, String[]testMethods){
this.times = times;
this.testMethods = testMethods;
}
@Override
public Statement apply(final Statementbase, final FrameworkMethod method, Object target) {
return new Statement() {
@Override
public void evaluate() throwsThrowable {
int loopTime = 1;
if(Arrays.asList(testMethods).contains(method.getName())){
loopTime= times;
}
for(int i=0;i<loopTime;i++){
base.evaluate();
}
}
};
}
}
調用自定義的rule
importorg.junit.After;
importorg.junit.Before;
importorg.junit.Rule;
importorg.junit.Test;
importorg.junit.rules.MethodRule;
public class TestCase {
@Rule
public MethodRule rule = new RepeatableRule(5, new String[]{"test1"});
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void test() {
System.out.println("test");
}
@Test
public void test1() {
System.out.println("test1");
}
}
執行用例可以看到用例 test1被執行了5次。
用例并發執行與出錯重試機制
Junit4并發不便利往往是其被TestNG使用者诟病的原因,其實我們可以使用Maven的maven-surefire-plugin插件解決這個問題,而這一方法也是在持續內建過程中運作自動化測試用例最常用的解決方案之一。maven-surefire-plugin是一個用于mvn 生命周期的測試階段的插件,可以通過一些參數設定友善的在testNG或junit下對測試階段進行自定義。在實際工作中我們可以利用該插件指定運作的測試用例,并通過多線程的方式來運作用例,我們僅僅需要配置參數<threadCount>即可,例如:<threadCount>3</threadCount>,表示用3個線程執行測試使用。更為友善的是我們還可以通過參數<rerunFailingTestsCount>來控制重新運作失敗的測試用例的執行次數。例如:<rerunFailingTestsCount>2</rerunFailingTestsCount>,表示用例失敗後将再重新執行2次。關于詳細使用maven-surefire-plugin插件的方法請參考文章:
詳解maven-surefire-plugin在自動化測試中的應用