zoukankan      html  css  js  c++  java
  • Junit4参数化测试实现程序与用例数据分离

    http://touchfu.iteye.com/blog/732930

    现状:你是不是还在为自己的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部分也分离出去,这样才能更好的达到扩展的效果。

  • 相关阅读:
    Sql Server--如何自动备份数据
    Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AS" and "Chinese_PRC_CI_AI" in the equal to operation.
    GET方法和POST方法的区别,Get方法到底可传递的字符串的最大长度是多少?
    Specialization For SCCM
    Fullscreen API:全屏操作
    How to enable remote connections to SQL Server
    Advanced Installer
    ajax跨域请求webservice webconfig配置
    SharePoint Resize app
    Sharepoint 开启App 配置App
  • 原文地址:https://www.cnblogs.com/ceshi2016/p/6247614.html
Copyright © 2011-2022 走看看