测试开发之路—可读性,可维护性,可扩展性(2)

发表于:2016-6-02 08:27

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:ycwdaaaa    来源:51Testing软件测试网采编

  // 获取待测接口对象的工厂长对象
  IInvokeObjectFactory factory = InvokeObjectFactoryFactory.getInvokeObjectFactory(info.getInvokeType());
  Object invokeObject = factory.getInvokeObject(info.getClassName());
  OK,看到了吧,客户端不清楚算法具体怎么实现的,也不知道是在调用哪个算法,反正我只需要知道这些算法的接口就行了。 传递一个 算法名称 就可以创建算法了,而算法名称其实也是外部传递进来的。所以实际上客户端除了这个接口以外,什么都不需要知道(知道的最少原则)。以上的例子是使用了spring的bean工厂, 工厂模式 和 策略模式(如果没有大家没有使用spring的话,自己写享元模式或者用java反射也是可以的)。想想看这是不是比用if else管理大篇的代码方便多了。扩展起来也很容易。不必修改原来的代码。只需要新加一个算法就可以。 符合面向对象的 开闭原则 。
  可插拔式设计
  用过testng的或者tomcat的人一定对这种设计不陌生,tomcat的配置文件里准许用户自定义connector然后注册进tomcat里代替默认的。testng也可以自己实现监听器然后注册进testng中用以定制化report。据我所知QTP的关键字驱动框架中也有自定义关键字的的功能(没用过,听同事说的)。下面看一下testng的例子。
  <listeners>
  <listener class-name="InterfaceTool.testListener.ReporterListener"></listener>
  <listener class-name="InterfaceTool.testListener.TestListener"></listener>
  <listener class-name="InterfaceTool.testListener.SuiteListener"></listener>
  <!--
  <listener class-name="com.bj58.daojia.test.InterfaceTool.testListener.RetryListener"></listener>
  -->
  </listeners>
  可以看到上面就是testng的可插拔机制。我自己实现一个listener然后注册进来。这样testng使用的就是我的ReporterListener生成测试报告了。这些都是可插拔式的设计,基于控制反转的思想,我们定义了好了行为,控制实现留给用户扩展。 有时候这种设计可能很有必要,因为可能你写的框架在一个公司里有很多业务线在用,你无法预测出所有的情况,所以干脆留个接口让他们扩展。或者你也有关键字驱动的框架,你需要能让用户有能力自定义自己的关键字。所以这种设计就变得很有必要。下面我们说说具体的实现原理。通过帖子最开始的那个例子,我们现在已经把算法抽象出来了,留下了一个接口。所有的算法都实现这个接口,我们的客户端也是面向这个接口编程的,也就是说,你是用什么算法我不关心,只要你的算法实现了这个接口就行了。也有一个专门的工厂类来帮客户端创建这些算法。如果像tomcat或者是testng这种算法是唯一的,也就是只能使用一种算法。那么其实这个工厂类也就不用参数了。如果是关键字驱动这种有很多算法的,我们创建算法的工厂类就需要一个name来做参数,判断创建哪个算法。然后我们在运行时读取测试人员编写的用例中使用的哪种关键字当作参数就可以了。例如下面的例子:
  <methods url="api/model/deleteModel" httptype="post" invokeType="http" verifyMethod="">
  可以看到上面的xml文件就是测试人员要填写的。中间的那个invokeType 就是说我用哪种方式获取接口。这种 把决定使用哪种实现的权利交给用户的机制,很好的体现了控制反转的思想,同时我们编程的时候也完全不用考虑到底是在用哪个算法,这样就充分的解耦了。那么现在我们其实还需要一种注册方式,把用户自己定义的方法注册进框架里。如果测试框架和项目都使用spring管理的话就简单了,像第一个例子一样,直接交给bean工厂管理就行了。写算法的时候一个@component注解就行了。如果大家不是用spring管理的,那么就需要使用 享元模式 加java反射来搞这个事情了。 首先我们搞一个XML的配置文件,定一个标签让用户去注册算法,就像上面testng的做法一样。然后我们在帖子第一个例子中的创建算法的工厂类中,就要像下面这么写(其实就是个 享元模式 )
public class InvokeObjectFactoryFactory {
private static ConcurrentHashMap<String, IInvokeObjectFactory> map = new ConcurrentHashMap<String, IInvokeObjectFactory>();
public static IInvokeObjectFactory getInvokeObjectFactory(String path,String name)
if (map.containsKey(name)) {
return map.get(name);
} else {
IInvokeObjectFactory factory = null;
try {
factory = (IInvokeObjectFactory) Tools
.reflectObject(path);
map.putIfAbsent(factory , name);
} catch (Exception e) {
e.printStackTrace();
Assert.assertTrue("无法生成对应的调用方式:" + path+ " 请检查是否调用方式输入错误", false);
}
return factory;
}
}
  我们看到通过一个name和一个自己实现的算法的路径为参数。 是用java反射的方式创建这个路径的算法,然后用name为key存到一个map中。以后其他模块调用算法的时候,就会去这个map里获取算法了。这样我们就把自定义的算法注册到了框架里。
  总结
  我们来说说这样做的好处。其实最大的好处就是 扩展性 和 维护性 强,以后新加算法的时候我们随便在哪实现预先定义的算法接口然后注册进框架就行了。 我们不需要改动哪怕一行原来的框架代码。相比我们用if else去hold住所有情况的方式,加一个算法你就要跑去框架里相应的位置去加一段if 分支的方式实在是痛苦之极,尤其是你需要对你原来的框架作不小的改动。而这个改动可能只适应你公司的一条业务线,不同的业务可能需要不同的算法。而每出现一个新算法业务线的人都跑来让你加进去你说你烦不烦。举个例子你是做关键字驱动框架的, 那么每个关键字都必然是你来写了,因为每个测试人员想要定义一个新关键字的时候都跑来找你写(他们自己写不了,框架代码他们也看不懂,就算他们知道了在哪里加if分支在哪里加算法,你敢让别人随便动你的框架么?),而且这种一换项目就会废弃掉的算法在你的框架里呆着也是不妥的。假如你跳槽了,你说这些算法你是删还是不删。还是退一万步讲,一旦你离开了这个岗位。接手这个框架的人真得通读一遍框架代码才知道怎么扩展关键字了。如果假如这个框架还没文档没注释的。。。那他会不会疯掉。。。
  所以我十分鼓励设计可插拔式的框架,准许用户自定义实现他们想做的事情。
  注意:文章中所有的设计方式不仅仅在关键字驱动中才有用。很多地方你都可以用到它 。
相关文章
测试开发之路—一切为了效率 (简易监控)
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号