Junit4参数化测试实现程序与用例数据分离

来源:互联网 发布:手机网络加速器破解版 编辑:程序博客网 时间:2024/05/16 08:01

Junit4参数化测试实现程序与用例数据分离

 

  现状:你是不是还在为自己的TestCase代码杂乱无章而苦恼,咎其根本还在于针对不同的用例,输入参数和mock信息的组装全部作为你的程序代码分布在各个单元测试程序中。

  期望:因此为了让测试程序更加优雅的显示作为code的本质,我们需要把输入参数和mock内容与程序本身尽可能的达到松耦合的布局,即程序归程序,用例数据归用例数据。

  如何:我们怎么来完成这样的一个分离动作呢,下面讲讲本人实现的基本思路。利用JUNIT4中的参数化测试为基础,通过解析文件来初始化参数信息,并对用例提供注销控制。

  下面我们着重介绍下实现BaseTestCase.

 

Java代码  收藏代码
  1. @RunWith(Parameterized.class)  
  2. @ContextConfiguration(locations = {"XXX.xml"})  
  3. public class BaseTestCase extends AbstractJUnit4SpringContextTests{  
  4.     /** 用例ID */  
  5.     protected String                     caseId;  
  6.     /** 描述 */  
  7.     protected String                     description;  
  8.     /** 期望值 */  
  9.     protected String                     expectValue;  
  10.     /** 测试上下文管理 */  
  11.     private final TestContextManager     testContextManager;  
  12.   
  13.     public BaseTestCase(){  
  14.         this.testContextManager = new TestContextManager(getClass());  
  15.         this.caseId = caseId;  
  16.         this.description = description;  
  17.         this.expectValue = expectValue;  
  18.     }  
  19.   
  20.     /** 
  21.      * 依靠<code>DependencyInjectionTestExecutionListener<code>完成注入上下文信息 
  22.      * @throws Throwable 
  23.      */  
  24.     @Before  
  25.     public void injectDependencies() throws Throwable {  
  26.         this.testContextManager.prepareTestInstance(this);  
  27.     }  
  28.   
  29.     /** 
  30.      * 获取用例数据 
  31.      * @param caseFilePath 
  32.      * @return 
  33.      */  
  34.     protected static Collection<String[]> loadCaseData(String caseFilePath) {  
  35.         if (StringUtil.isBlank(caseFilePath)) {  
  36.             throw new IllegalArgumentException("未初始化用例文件信息");  
  37.         }  
  38.         List<String[]> caseDataList = FileParser.loadItems("cases/" + caseFilePath);  
  39.         if (CollectionUtils.isEmpty(caseDataList)) {  
  40.             throw new IllegalArgumentException("准备数据不能为空");  
  41.         }  
  42.         // 剔除第一行标题信息  
  43.         caseDataList.remove(0);  
  44.   
  45.         return caseDataList;  
  46.     }  
  47. }  

 由于在自己基类使用的runner为Parameterized,与使用SpringJUnit4ClassRunner的不同在于少了自动对测试上下文进行依赖注入关联,因此我们需要自己手工触发完成,大家在类源码里可以注意到这一点。主要还是依赖于DependencyInjectionTestExecutionListener完成。同时由于测试基类集成了AbstractJUnit4SpringContextTests了,在此类的源码里可以看到两个关键点DependencyInjectionTestExecutionListener和其中的ApplicationContext,因此我们在子类里不需要再自己写什么上下文的属性,也不需要再添加依赖注入的执行监听器。

  下面再看下FileParser的实现

 

Java代码  收藏代码
  1. /** 
  2.  * <p>文件解析器</p> 
  3.  * @author Eric.fu 
  4.  */  
  5. public class FileParser {  
  6.     /** 分隔符 */  
  7.     private static final String SPLIT_TAG  = ",";  
  8.     /** 忽略标记 */  
  9.     private static final String IGNORE_TAG = "#";  
  10.   
  11.     /** 
  12.      * 获取文件内容 
  13.      * @param filePath 
  14.      * @return 
  15.      */  
  16.     public static List<String[]> loadItems(String filePath) {  
  17.         List<String[]> itemList = new ArrayList<String[]>();  
  18.         ClassPathResource resource = new ClassPathResource(".");  
  19.         BufferedReader reader = null;  
  20.         try {  
  21.             String path = resource.getFile().getAbsolutePath();  
  22.             File file = new File(path + "/META-INF/" + filePath);  
  23.             reader = new BufferedReader(new FileReader(file));  
  24.   
  25.             String tempString = null;  
  26.             // 一次读入一行,直到读入空为文件结束  
  27.             while (StringUtil.isNotBlank(tempString = reader.readLine())) {  
  28.                 if (tempString.indexOf(IGNORE_TAG) == 0) {  
  29.                     continue;  
  30.                 }  
  31.                 itemList.add(tempString.split(SPLIT_TAG));  
  32.             }  
  33.             reader.close();  
  34.         } catch (IOException e) {  
  35.             e.printStackTrace();  
  36.         } finally {  
  37.             if (reader != null) {  
  38.                 try {  
  39.                     reader.close();  
  40.                 } catch (IOException e1) {  
  41.                 }  
  42.             }  
  43.         }  
  44.   
  45.         return itemList;  
  46.     }  
  47. }  

 

 此类为相当普通的一段读文件的代码,这里有个特殊点在于加了一个忽略标记,用于注释用例数据,即把不跑的数据暂时注释掉,不作为读入参数。

  下面再来看下一个简单的测试子类实现

 

Java代码  收藏代码
  1. public class SubTestCase extends BaseTestCase {  
  2.     /** 测试请求 */  
  3.     protected String            request;  
  4.     /** 
  5.      * 构造入款支付清算 
  6.      */  
  7.     public SubTestCase(String caseId, String description, String expectValue, String request){  
  8.         super(caseId, description, expectValue);  
  9.         this.request = request;  
  10.     }  
  11.    
  12.     @Parameters  
  13.     public static Collection<String[]> caseData() {  
  14.         return loadCaseData("case.csv");  
  15.     }  
  16.   
  17.     /** 
  18.      * 执行 
  19.      */  
  20.     @Test  
  21.     public void execute() {  
  22.         Assert.notNull(request);  
  23.     }  
  24. }  
 

 

在子类里通过构造方法初始化参数,参数数据来源为case.csv文件。

文件格式为caseId,description,expectValue,request

 

本文主要介绍的利用JUNIT4中的参数化测试来完成程序与测试数据的分离,当然如果你用的testNG,则可以用更优雅的provider来完成此项工作。在测试用例中除了让数据与程序分离还是不够的,还需要将mock部分也分离出去,这样才能更好的达到扩展的效果。

0 0