引言
這篇文章將幫你了解如下內(nèi)容:
單元測(cè)試框架如何在自動(dòng)化測(cè)試中應(yīng)用;
junit4如何上手;
junit4的高級(jí)功能有哪些;
junit4中用例并發(fā)和用例失敗重試的方案;
單元測(cè)試
單元測(cè)試(Unit Testing),是一種軟件測(cè)試方法,通過(guò)這種測(cè)試方法測(cè)試各個(gè)源代碼單元,一個(gè)或者多個(gè)模塊的集合,使用程序來(lái)測(cè)試程序,來(lái)保證它們的可用性。一般來(lái)說(shuō)單元測(cè)試由開(kāi)發(fā)人員自己來(lái)執(zhí)行。單元測(cè)試是由開(kāi)發(fā)人員編寫(xiě)的一段代碼,用于檢查被測(cè)試代碼的一個(gè)小的、明確的功能是否正確。由于近些年來(lái)ui自動(dòng)化測(cè)試和接口測(cè)試的流行,單元測(cè)試也被引入到自動(dòng)化測(cè)試領(lǐng)域,我們通常編寫(xiě)的自動(dòng)化測(cè)試腳本都是基于單元測(cè)試框架。不同的語(yǔ)言有其對(duì)應(yīng)的單元測(cè)試框架。例如:Java的主流單元測(cè)試框架包括:Junit4\TestNG;Python的主流單元測(cè)試框架包括:unittest\pytest等等。
Junit概念
Junit是一個(gè)可編寫(xiě)重復(fù)測(cè)試的簡(jiǎn)單框架,是基于Xunit架構(gòu)的單元測(cè)試框架的實(shí)例。Junit4最大的改進(jìn)是大量使用注解(元數(shù)據(jù)),很多實(shí)際執(zhí)行 過(guò)程都在Junit的后臺(tái)做完了,而且寫(xiě)test case 的類(lèi)不需要繼承TestCase,只需要在所要做test case的方法前加@Test 注解即可。Junit被默認(rèn)的作為Eclipse插件,集成到Eclipse中。
新特性:
(1)、使用junit4.x版本進(jìn)行單元測(cè)試時(shí),不用測(cè)試類(lèi)繼承TestCase父類(lèi)
(2)、junit4.x版本,引用了注解的方式,進(jìn)行單元測(cè)試;
Junit4環(huán)境搭建
Java 工程中add Library
選擇Junit4 點(diǎn)擊Finish按鈕
Junit4的常用注解
junit4.x版本我們常用的注解:
A、@Before 注解:與junit3.x中的setUp()方法功能一樣,在每個(gè)測(cè)試方法之前執(zhí)行;
B、@After 注解:與junit3.x中的tearDown()方法功能一樣,在每個(gè)測(cè)試方法之后執(zhí)行;
C、@BeforeClass 注解:在所有方法執(zhí)行之前執(zhí)行;
D、@AfterClass 注解:在所有方法執(zhí)行之后執(zhí)行;
JUnit4的用例執(zhí)行順序是:@BeforeClass> @Before> @Test1> @After>@Before> @Test2> @After….. @AfterClass
E、@Test(timeout = xxx) 注解:設(shè)置當(dāng)前測(cè)試方法在一定時(shí)間內(nèi)運(yùn)行完,否則返回錯(cuò)誤;
F、@Test(expected =Exception.class) 注解:設(shè)置被測(cè)試的方法是否有異常拋出。拋出異常類(lèi)型為:Exception.class;
G、@Ignore 注解:注釋掉一個(gè)測(cè)試方法或一個(gè)類(lèi),被注釋的方法或類(lèi),不會(huì)被執(zhí)行。
H、@RunWith注解:指定用例的運(yùn)行Runner,是用來(lái)修飾類(lèi)的,而不是用來(lái)修飾函數(shù)的。只要對(duì)一個(gè)類(lèi)指定了 Runner ,那么這個(gè)類(lèi)中的所有函數(shù)都被這個(gè) Runner 來(lái)調(diào)用。
assertThat
JUnit 4.4 結(jié)合 Hamcrest 提供了一個(gè)全新的斷言語(yǔ)法——assertThat。assertThat 使用了Hamcrest 的Matcher 匹配符,用戶(hù)可以使用匹配符規(guī)定的匹配準(zhǔn)則精確的指定一些想設(shè)定滿足的條件,具有很強(qiáng)的易讀性,而且使用起來(lái)更加靈活。使用assertThat 需要導(dǎo)入:
import static org.hamcrest.CoreMatchers.*;
assertThat的主要功能如下:
一般匹配符
1、assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );
注釋?zhuān)?allOf匹配符表明如果接下來(lái)的所有條件必須都成立測(cè)試才通過(guò),相當(dāng)于“與”(&&)
2、assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
注釋?zhuān)篴nyOf匹配符表明如果接下來(lái)的所有條件只要有一個(gè)成立則測(cè)試通過(guò),相當(dāng)于“或”(||)
3、assertThat(testedNumber, anything() );
注釋?zhuān)篴nything匹配符表明無(wú)論什么條件,永遠(yuǎn)為true
4、assertThat(testedString, is( "developerWorks" ) );
注釋?zhuān)?is匹配符表明如果前面待測(cè)的object等于后面給出的object,則測(cè)試通過(guò)
5、assertThat(testedString, not( "developerWorks" ) );
注釋?zhuān)簄ot匹配符和is匹配符正好相反,表明如果前面待測(cè)的object不等于后面給出的object,則測(cè)試通過(guò)
字符串相關(guān)匹配符
1、assertThat( testedString,containsString( "developerWorks" ) );
注釋?zhuān)篶ontainsString匹配符表明如果測(cè)試的字符串testedString包含子字符串"developerWorks"則測(cè)試通過(guò)
2、assertThat(testedString, endsWith ( "developerWorks" ) );
注釋?zhuān)篹ndsWith匹配符表明如果測(cè)試的字符串testedString以子字符串"developerWorks"結(jié)尾則測(cè)試通過(guò)
3、assertThat(testedString, startsWith ( "developerWorks" ) );
注釋?zhuān)簊tartsWith匹配符表明如果測(cè)試的字符串testedString以子字符串"developerWorks"開(kāi)始則測(cè)試通過(guò)
4、assertThat(testedValue, equalTo( expectedValue ) );
注釋?zhuān)?equalTo匹配符表明如果測(cè)試的testedValue等于expectedValue則測(cè)試通過(guò),equalTo可以測(cè)試數(shù)值之間,字符串之間和對(duì)象之間是否相等,相當(dāng)于Object的equals方法
5、assertThat(testedString, equalToIgnoringCase( "developerWorks" ) );
注釋?zhuān)篹qualToIgnoringCase匹配符表明如果測(cè)試的字符串testedString在忽略大小寫(xiě)的情況下等于"developerWorks"則測(cè)試通過(guò)
6、assertThat(testedString, equalToIgnoringWhiteSpace( "developerWorks" ) );
注釋?zhuān)篹qualToIgnoringWhiteSpace匹配符表明如果測(cè)試的字符串testedString在忽略頭尾的任意個(gè)空格的情況下等于"developerWorks"則測(cè)試通過(guò),注意:字符串中的空格不能被忽略
數(shù)值相關(guān)匹配符
1、assertThat(testedDouble, closeTo( 20.0, 0.5 ) );
注釋?zhuān)篶loseTo匹配符表明如果所測(cè)試的浮點(diǎn)型數(shù)testedDouble在20.0±0.5范圍之內(nèi)則測(cè)試通過(guò)
2、assertThat(testedNumber, greaterThan(16.0) );
注釋?zhuān)篻reaterThan匹配符表明如果所測(cè)試的數(shù)值testedNumber大于16.0則測(cè)試通過(guò)
3、assertThat(testedNumber, lessThan (16.0) );
注釋?zhuān)簂essThan匹配符表明如果所測(cè)試的數(shù)值testedNumber小于16.0則測(cè)試通過(guò)
4、assertThat(testedNumber, greaterThanOrEqualTo (16.0) );
注釋?zhuān)?greaterThanOrEqualTo匹配符表明如果所測(cè)試的數(shù)值testedNumber大于等于16.0則測(cè)試通過(guò)
5、assertThat(testedNumber, lessThanOrEqualTo (16.0) );
注釋?zhuān)簂essThanOrEqualTo匹配符表明如果所測(cè)試的數(shù)值testedNumber小于等于16.0則測(cè)試通過(guò)
collection相關(guān)匹配符
1、assertThat( mapObject,hasEntry( "key", "value" ) );
注釋?zhuān)篽asEntry匹配符表明如果測(cè)試的Map對(duì)象mapObject含有一個(gè)鍵值為"key"對(duì)應(yīng)元素值為"value"的Entry項(xiàng)則測(cè)試通過(guò)
2、assertThat(iterableObject, hasItem ( "element" ) );
注釋?zhuān)篽asItem匹配符表明如果測(cè)試的迭代對(duì)象iterableObject含有元素“element”項(xiàng)則測(cè)試通過(guò)
3、assertThat( mapObject,hasKey ( "key" ) );
注釋?zhuān)?hasKey匹配符表明如果測(cè)試的Map對(duì)象mapObject含有鍵值“key”則測(cè)試通過(guò)
4、assertThat( mapObject,hasValue ( "key" ) );
注釋?zhuān)篽asValue匹配符表明如果測(cè)試的Map對(duì)象mapObject含有元素值“value”則測(cè)試通過(guò)
Junit4應(yīng)用
創(chuàng)建一個(gè)junit4用例
New>選則JUnit Test Case
選擇New Junit4 test,點(diǎn)擊Finish即完成了一個(gè)Junit4 用例的創(chuàng)建工作
實(shí)例代碼
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");
????????????? }
}
執(zhí)行多個(gè)測(cè)試用例
執(zhí)行多個(gè)測(cè)試用例的意義是將多個(gè)測(cè)試用例通過(guò)suite管理起來(lái)。
New一個(gè)Test Suite,點(diǎn)擊Next
可以自定義需要執(zhí)行的測(cè)試用例
點(diǎn)擊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擴(kuò)展Junit4
Rule是JUnit4中的新特性,它讓我們可以擴(kuò)展JUnit的功能,靈活地改變測(cè)試方法的行為。JUnit4中包含兩個(gè)注解@Rule和@ClassRule用于修飾Field或返回Rule的?Method,Rule是一組實(shí)現(xiàn)了TestRule接口的共享類(lèi),提供了驗(yàn)證、監(jiān)視TestCase和外部資源管理等能力。JUnit提供了以下幾個(gè)Rule實(shí)現(xiàn),必要時(shí)也可以自己實(shí)現(xiàn)Rule。
Verifier: 驗(yàn)證測(cè)試執(zhí)行結(jié)果的正確性。
ErrorCollector: 收集測(cè)試方法中出現(xiàn)的錯(cuò)誤信息,測(cè)試不會(huì)中斷,如果有錯(cuò)誤發(fā)生測(cè)試結(jié)束后會(huì)標(biāo)記失敗。
ExpectedException: 提供靈活的異常驗(yàn)證功能。
Timeout: 用于測(cè)試超時(shí)的Rule。
ExternalResource: 外部資源管理。
TemporaryFolder: 在JUnit的測(cè)試執(zhí)行前后,創(chuàng)建和刪除新的臨時(shí)目錄。
TestWatcher: 監(jiān)視測(cè)試方法生命周期的各個(gè)階段。
TestName: 在測(cè)試方法執(zhí)行過(guò)程中提供獲取測(cè)試名字的能力。
簡(jiǎn)單的說(shuō)就是提供了測(cè)試用例執(zhí)行過(guò)程中一些通用功能的共享的能力,使我們不必重復(fù)編寫(xiě)一些功能類(lèi)似的代碼。JUnit用于標(biāo)注Rule的注解包括@Rule和@ClassRule,區(qū)別在于作用域不同@Rule的作用域是測(cè)試方法,@ClassRule則是測(cè)試Class。
自定義Rule實(shí)例:
自定義一個(gè)rule, 實(shí)現(xiàn)循環(huán)執(zhí)行一個(gè)方法,代碼如下:
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();
???????? }
????? };
?????? }
}
調(diào)用自定義的rule
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.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");
?????? }
}
執(zhí)行用例可以看到用例 test1被執(zhí)行了5次。
用例并發(fā)執(zhí)行與出錯(cuò)重試機(jī)制
Junit4并發(fā)不便利往往是其被TestNG用戶(hù)詬病的原因,其實(shí)我們可以使用Maven的maven-surefire-plugin插件解決這個(gè)問(wèn)題,而這一方法也是在持續(xù)集成過(guò)程中運(yùn)行自動(dòng)化測(cè)試用例最常用的解決方案之一。maven-surefire-plugin是一個(gè)用于mvn?生命周期的測(cè)試階段的插件,可以通過(guò)一些參數(shù)設(shè)置方便的在testNG或junit下對(duì)測(cè)試階段進(jìn)行自定義。在實(shí)際工作中我們可以利用該插件指定運(yùn)行的測(cè)試用例,并通過(guò)多線程的方式來(lái)運(yùn)行用例,我們僅僅需要配置參數(shù)<threadCount>即可,例如:<threadCount>3</threadCount>,表示用3個(gè)線程執(zhí)行測(cè)試使用。更為方便的是我們還可以通過(guò)參數(shù)<rerunFailingTestsCount>來(lái)控制重新運(yùn)行失敗的測(cè)試用例的執(zhí)行次數(shù)。例如:<rerunFailingTestsCount>2</rerunFailingTestsCount>,表示用例失敗后將再重新執(zhí)行2次。關(guān)于詳細(xì)使用maven-surefire-plugin插件的方法請(qǐng)參考文章: