您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 > junit
JUnit擴展:引入新注解Annotation
作者:網(wǎng)絡轉載 發(fā)布時間:[ 2015/4/17 10:48:13 ] 推薦標簽:Junit 單元測試 Annotation

  發(fā)現(xiàn)問題
  JUnit提供了Test Suite來幫助我們組織case,還提供了Category來幫助我們來給建立大的Test Set,比如BAT,MAT, Full Testing。 那么什么情況下,這些仍然不能滿足我們的需求,需要進行拓展呢?
  閑話不表,直接上需求:
  1. 老板希望能精確的衡量出每個Sprint寫了多少條自動化case,或者每個User Story又設計了多少條case來保證覆蓋率,以此來對工作量和效率有數(shù)據(jù)上的直觀表示。
  2. 對于云服務,通常會有不同的server來對應產(chǎn)品不同的開發(fā)階段,比如dev的server,這里大家可以隨意上傳代碼,ScrumQA會測試每一個開發(fā)提交的Feature -> 然后當產(chǎn)品部署到測試server時,Scrum QA 和 System QA 得對產(chǎn)品進行充分的測試 -> 甚或者有預發(fā)布的server,來模擬真實產(chǎn)品環(huán)境,這個server,仍然需要測試 -> 后產(chǎn)品會部署到真正的生產(chǎn)環(huán)境上。
  這時候衍生了測試代碼版本控制的問題,比如當我針對新需求寫的自動化case所測得Feature,當前只在Dev上部署,還沒有在其他的server部署,那我的case怎么辦?在其他的server上運行一定會失敗。
  3. 當產(chǎn)品足夠復雜時,我們可能有成千上萬條case,這樣全部運行這些case,時間上可能非常耗時。 而如果使用JUnit的category來分組可能顆粒度太粗,不靈活,怎么辦?
  解決方案
  綜合考慮,為解決以上需求,我們覺得必須在Case級別上做文章,所以結合JUnit4的功能,我們終引入了新的注解Annotation:Spint, UserStory, 和 Defect。
  名稱                                   描述                                               作用域
  Sprint用來標記這條Case是在什么時候引進的,或者說這條Case是哪個Sprint的加入的功能              方法
  UserStory用來標記這條Case測試的是哪個UserStory,或者說覆蓋的那個UserStory,這樣即使過了很長時間,我們也能清晰地知道,我們?yōu)槭裁醇舆@條Case,以及它到底測的是什么功能              方法
  Defect用來標記這條Case覆蓋的Defect,或者說覆蓋的Defect              方法
  在實際使用時,我們可以這么用:
  @Test
  @Sprint("15.3")
  @UserStory("US30145")
  @Defect(CR = "30775", Title = "[cr30775][p0] xxxx...")
  public void test_AddUserDirectDebitInformation_204_WithoutXXXBefore()
  {
  // Case Body
  }
  那么在運行時,根據(jù)這些標記,我們可以隨心所欲的Filter出我們需要的Case了:
  只運行某個特定Sprint的case
  運行某個Sprint下的某個UserStory所屬的Case
  運行所有的有Bug的Case,單做回歸測試
  。。。
  當然統(tǒng)計每個Sprint的工作量也有了可能。
  代碼實現(xiàn)
  研究過類似問題的童鞋可能知道,IBM的網(wǎng)站上,有一篇文章,講過這個問題(地址在文章底有列)。并且他還定義了更多的注解需求, 也給出了部分實現(xiàn)。這篇文章有個好處是先從JUnit整體架構運行流程出發(fā),采用各個模塊包裝的方法,然后從入口JUnitCore出發(fā)去重新發(fā)起Request來運行我們自定義的Case,我覺得研究這篇文章可以對不了解JUnit核心框架的童鞋有一定的幫助。
  這篇文章已經(jīng)給出了自定義Runner部分的代碼,缺了兩塊。第一是IntentObject部分,它把參數(shù)封裝成對象。第二部分是定義實現(xiàn)Filter。我這里給出它缺的那部分Filter的實現(xiàn),Intent這塊直接當String處理可以了。
public class FilterFactory
{
public static final String REGEX_COMMA = ",";
public static final String ANNOTATION_PREFIX = "com.junit.extension.annotations."; // 包名的前綴
public static final String REGEX_EQUAL = "=";
public static List<Filter> filters = new ArrayList<Filter>();
public static List<Filter> getFilters()
{
return filters;
}
// This is a special toggle served {@link Sprint}
public static String FILTER_RUN_CASE_ISONLY_TOGGLE = "isOnly";
private static FilterSprint fSprint = null;
private static FilterUserStory fUserStory = null;
private static FilterDefect fDefect = null;
public static List<Filter> createFilters(String intention) throws ClassNotFoundException
{
String[] splits = intention.split(REGEX_COMMA);
for(String split : splits)
{
String[] pair = split.split(REGEX_EQUAL);
if(pair != null && pair.length == 2)
{
if(pair[0].trim().equalsIgnoreCase(FILTER_RUN_CASE_ISONLY_TOGGLE))
{
if(fSprint == null)
{
fSprint = new FilterSprint();
}
fSprint.setIsOnly(Boolean.parseBoolean(pair[1].trim()));
}
else
{
Class<?> annotation = Class.forName(ANNOTATION_PREFIX + pair[0].trim());
if(annotation.isAssignableFrom(Sprint.class))
{
fSprint = new FilterSprint(pair[1].trim());
}
else if(annotation.isAssignableFrom(UserStory.class))
{
fUserStory = new FilterUserStory(pair[1].trim());
filters.add(fUserStory);
}
else if(annotation.isAssignableFrom(Defect.class))
{
fDefect = new FilterDefect(pair[1].trim());
filters.add(fDefect);
}
}
if(fSprint != null)
{
filters.add(fSprint);
}
}
}
return filters;
}

上一頁123下一頁
軟件測試工具 | 聯(lián)系我們 | 投訴建議 | 誠聘英才 | 申請使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd