代码测试(CodeTest)

    xiaoxiao2022-07-16  153

    1.  什么是代码测试?与传统的功能和接口测试有什么不同?   代码测试的立足点是Code,是基于代码基础之上的,而传统的 功能测试和接口测试是基于应用的,必须对应的测试系统是在运行中的。   代码测试不会特别注重接口测试的可持续性集成。   代码测试的特点是快捷高效准确的完成测试 工作,快速推进产品的迭代。    2.  Code Test 的方法:   (1)  代码走读和review   适合场景:逻辑相对简单,有较多的边界值。   方法介绍:直接查看和阅读代码,检验逻辑是否正确。   (2)  代码debug与代码运行中测试   适合场景:数据构造比较困难,特殊的场景覆盖。   方法介绍:1.直接在debug代码过程中查看数据流走向,校验逻辑。   2.在debug过程中直接将变量的值或者对象的值直接改成想要的场景   (3)  私有方法测试   适合场景:需要测试的类的复杂逻辑处理是放在一个特定的方法中,而且该方法中没有使用到其他引用的bean   方法介绍:通过反射的方式调用方法,进行测试。   例子:   假设有一个待测试的类叫MyApp,有一个私有方法叫getSortList, 参数是一个整形List。 /** * Created by yunmu.wgl on 2014/7/16. */ public class MyApp { private List  getSortList(List<Integer> srcList){ Collections.sort(srcList); return srcList; } }   那么测试类的代码如下: /** * Created by yunmu.wgl on 2014/7/16. */ public class MyAppTest { @Test public  void testMyApp() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class clazz = MyApp.class; Method sortList = clazz.getDeclaredMethod("getSortList",List.class); //获取待测试的方法 sortList.setAccessible(true); //私有方法这个是关键 List<Integer> testList = new ArrayList<Integer>();//构造测试数据 testList.add(1); testList.add(3); testList.add(2); MyApp myApp = new MyApp(); // 新建一个待测试类的对象 sortList.invoke(myApp,testList); //执行测试方法 System.out.println(testList.toString()); //校验测试结果 } }  (4)  快速搭建测试脚本环境   适合场景:待测试的方法以hsf提供接口方法,或者需要测试的类引入了其他bean 配置。   方法介绍:直接在开发工程中添加测试依赖,主要是junit,如果是需要测试hsf接口,则加入hsf的依赖,如果需要使用itest的功能,加入itest依赖。   Junit 的依赖一般开发都会加,主要看下junit的版本,最好是4.5 以上   HSF的测试依赖:以前的hsfunit 和hsf.unit 最好都不要使用了。   <dependency>   <groupId>com.taobao.hsf</groupId>   <artifactId>hsf-standalone</artifactId>   <version>2.0.4-SNAPSHOT</version>   </dependency>   Hsf 接口测试代码示例:   // 启动HSF容器,第一个参数设置taobao-hsf.sar路径,第二个参数设置HSF版本   HSFEasyStarter.start("d:/tmp/", "1.4.9.6");   String springResourcePath = "spring-hsf-uic-consumer.xml";   ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(springResourcePath);   UicReadService uicReadService = (UicReadService) ctx.getBean("uicReadService");   // 等待相关服务的地址推送(等同于sleep几秒,如果不加,会报找不到地址的错误)   ServiceUtil.waitServiceReady(uicReadService);   BaseUserDO user = uicReadService.getBaseUserByUserId(10000L, "detail").getModule();   System.out.println("user[id:10000L] nick:" + user.getNick());   Hsf bean的配置示例:   <beans>   <bean name="uicReadService" class="com.taobao.hsf.app.spring.util.HSFSpringConsumerBean"   init-method="init">   <property name="interfaceName" value="com.taobao.uic.common.service.userinfo.UicReadService" />   <property name="version" value="1.0.0.daily" />   </bean>   </beans>   Itest的依赖:这个版本之前修复了较多的bug。   <dependency>   <groupId>com.taobao.test</groupId>   <artifactId>itest</artifactId>   <version>1.3.2.1-SNAPSHOT</version>   <dependency>   (5)  程序流程图校验   适合场景:业务流程的逻辑较为复杂,分支和异常情况很多   方法介绍:根据代码逻辑画出业务流程图,跟实际的业务逻辑进行对比验证,是否符合预期。   (6)  结对编程   适合场景:代码改动较小,测试和开发配对比较稳定   方法介绍:开发修改完代码后,将修改部分的逻辑重复给测试同学,测试同学review 开发同学讲述的逻辑是否和代码的逻辑一致。   3.   具体操作步骤:   (1)  checkout代码,在接手项目和日常后第一件事情是checkout 对应的应用的代码   (2)  了解数据结构与数据存储关系:了解应用的数据对象和数据库的表结构及存储关系。   (3)  了解代码结构, 主要搞清楚代码的调用关系。   (4)  了解业务逻辑和代码的关系:业务逻辑肯定是在代码中实现的,找到被测试的业务逻辑对应的代码,比较常见的是通过url 或者接口名称等。   如果是webx框架的可以根据http请求找到对应的代码,如果是其他框架的也可以通过http请求的域名在配置文件中找到对应的代码。   (5)  阅读相关代码,了解数据流转过程。   (6)  Review 代码,验证条件,路径覆盖。   (7)  复杂逻辑可以选用写脚本测试或者私有方法测试,或者画出流程图。   4.  代码测试的常见测试场景举例:   (1)  条件,边界值,Null 测试:   复杂的多条件,多边界值如果要手工测试,会测试用例非常多。而且null值的测试往往构造数据比较困难。   例如如下的代码: if (mm.getIsRate() == UeModel.IS_RATE_YES) { float r; if (value != null && value.indexOf(‘.’) != -1) { r = currentValue – compareValue; } else { r = compareValue == 0 ? 0 : (currentValue – compareValue) / compareValue; } if (r >= mm.getIncrLowerBound()) { score = mm.getIncrScore(); } else if (r <= mm.getDecrUpperBound()) { score = mm.getDecrScore(); } mr.setIncreaseRate(formatFloat(r)); } else { // 目前停留时间为非比率对比 if (currentValue – compareValue >=mm.getIncrLowerBound()) { score = mm.getIncrScore(); } else if (currentValue – compareValue <= mm.getDecrUpperBound()) { score = mm.getDecrScore(); } } (2)  方法测试   某个方法相对比较独立,但是是复杂的逻辑处理   例如下面的代码: private void filtSameItems(List<SHContentDO> contentList) { Set<Integer> sameIdSet = new TreeSet<Integer>(); Set<Integer> hitIdSet = new HashSet<Integer>(); for (int i = 0; i < contentList.size(); i++) { if (sameIdSet.contains(i) || hitIdSet.contains(i)) { continue; } SHContentDO content = contentList.get(i); List<Integer> equals = new ArrayList<Integer>(); equals.add(i); if ("item".equals(content.getSchema())) { for (int j = i + 1; j < contentList.size(); j++) { SHContentDO other = contentList.get(j); if ("item".equals(other.getSchema()) && content.getReferItems().equals(other.getReferItems())) { equals.add(j); } } } if (equals.size() > 1) { Integer hit = equals.get(0); SHContentDO hitContent = contentList.get(hit); for (int k = 1; k < equals.size(); k++) { SHContentDO other = contentList.get(k); if (hitContent.getFinalScore() == other.getFinalScore()) { long hitTime = hitContent.getGmtCreate().getTime(); long otherTime = other.getGmtCreate().getTime(); if (hitTime > otherTime) { hit = equals.get(k); hitContent = other; } } else { if (hitContent.getFinalScore() < other.getFinalScore()) { hit = equals.get(k); hitContent = other; } } } for (Integer tmp : equals) { if (tmp != hit) { sameIdSet.add(tmp); } } hitIdSet.add(hit); } } Integer[] sameIdArray = new Integer[sameIdSet.size()]; sameIdSet.toArray(sameIdArray); for (int i = sameIdArray.length - 1; i >= 0; i--) { contentList.remove((int) sameIdArray[i]); } } 最新内容请见作者的GitHub页:http://qaseven.github.io/ 相关资源:codetest2006-2010
    最新回复(0)