任何阅读此博客的人都可能已经意识到,目前我正在开发一个包含大量旧代码的项目,这些旧代码庞大,扩展且编写时从未进行过任何测试。

在使用此遗留代码时,有一个行为异常的类非常普遍,整个团队都一次又一次地犯错。

为了保护这一罪恶,我将其称为X先生,尽管它的真名是SitePropertiesManager,因为它管理网站的属性。 表现不佳是因为:

  • 打破单一责任主体
  • 使用了由getInstance()工厂方法汇总的单例模式,
  • 有一个init()方法,必须在其他任何方法之前调用它,
  • 通过直接访问数据库而不是使用DAO加载其数据,
  • 使用复杂的地图来存储其数据,
  • 访问文件系统以缓存数据库返回的数据
  • 有一个计时器来决定何时更新其缓存。
  • 是在泛型之前编写的,具有大量多余的findXXXX()方法。
  • 没有实现接口,
  • 使用了大量的复制和粘贴程序。

这使得在编写新代码的单元测试时很难创建存根,并使旧代码杂乱无章:

SitePropertiesManager propman = SitePropertiesManager.getInstance();

该博客介绍了处理尴尬字符的方法,并演示了如何为它们创建存根,同时消除了Singleton模式的影响。 与以前的“测试技术”博客一样,我的演示代码也基于“地址”网络应用示例 。

在本系列的其他博客中,我一直在演示如何测试AddressService ,这个博客也没有什么不同。 但是,在这种情况下, AddressService必须加载站点属性并决定是否返回地址,但是在查看之前,我首先需要使用写得不好的SitePropertiesManager来使用。 但是,我不拥有该代码,因此我编写了一个特技双重版本,该版本打破了我能想到的许多规则。 我不会在这里让您感到厌烦,因为SitePropertiesManager的所有源代码都可以在以下位置找到:git://github.com/roghughe/captaindebug.git

如上所述,在这种情况下, AddressService使用站点属性来确定是否启用了它。 如果是,它将发送回一个地址对象。 我还要假装AddressService是一些使用站点属性静态工厂方法的旧代码,如下所示:

public Address findAddress(int id) {logger.info("In Address Service with id: " + id);Address address = Address.INVALID_ADDRESS;if (isAddressServiceEnabled()) {address = addressDao.findAddress(id);address = businessMethod(address);}logger.info("Leaving Address Service with id: " + id);return address;}private boolean isAddressServiceEnabled() {SitePropertiesManager propManager = SitePropertiesManager.getInstance();return new Boolean(propManager.findProperty("address.enabled"));}

在驯服这种类型的类时,他要做的第一件事是停止使用getInstance()获取保持和一个对象,将其从上述方法中删除,并开始使用依赖项注入。 必须至少调用一次getInstance() ,但这可以在程序的启动代码中进行。 在Spring的世界中,解决方案是将行为不佳的类包装在Spring FactoryBean实现中,该类成为应用程序中getInstance()的唯一位置–至少对于新代码/增强代码而言。

public class SitePropertiesManagerFactoryBean implementsFactoryBean {private static SitePropertiesManager propsManager = SitePropertiesManager.getInstance();@Overridepublic SitePropertiesManager getObject() throws Exception {return propsManager;}@Overridepublic Class getObjectType() {return SitePropertiesManager.class;}@Overridepublic boolean isSingleton() {return true;}
}

现在可以将其自动连接到AddressService类中:

@Autowiredvoid setPropertiesManager(SitePropertiesManager propManager) {this.propManager = propManager;}

但是,这些更改并不意味着我们可以为AddressService编写一些适当的单元测试,它们只是准备基础。 下一步是为SitePropertiesManager提取接口,使用eclipse可以轻松实现。

public interface PropertiesManager {public abstract String findProperty(String propertyName);public abstract String findProperty(String propertyName, String locale);public abstract List findListProperty(String propertyName);public abstract List findListProperty(String propertyName, String locale);public abstract int findIntProperty(String propertyName);public abstract int findIntProperty(String propertyName, String locale);}

在转移到接口时,我们还需要在Spring配置文件中手动配置SitePropertiesManager的实例,以便Spring知道将哪个类连接到哪个接口:

<beans:bean id="propman" class="com.captaindebug.siteproperties.SitePropertiesManager" />

我们还需要使用限定符更新AddressService的 @Autowired批注:

@Autowired@Qualifier("propman")void setPropertiesManager(PropertiesManager propManager) {this.propManager = propManager;}

通过一个接口,我们现在可以轻松编写一个简单的SitePropertiesManager存根:

public class StubPropertiesManager implements PropertiesManager {private final Map propMap = new HashMap();public void setProperty(String key, String value) {propMap.put(key, value);}@Overridepublic String findProperty(String propertyName) {return propMap.get(propertyName);}@Overridepublic String findProperty(String propertyName, String locale) {throw new UnsupportedOperationException();}@Overridepublic List findListProperty(String propertyName) {throw new UnsupportedOperationException();}@Overridepublic List findListProperty(String propertyName, String locale) {throw new UnsupportedOperationException();}@Overridepublic int findIntProperty(String propertyName) {throw new UnsupportedOperationException();}@Overridepublic int findIntProperty(String propertyName, String locale) {throw new UnsupportedOperationException();}
}

有了存根,很容易为使用存根并与数据库和文件系统隔离的AddressService编写单元测试

public class AddressServiceUnitTest {private StubAddressDao addressDao;private StubPropertiesManager stubProperties;private AddressService instance;@Beforepublic void setUp() {instance = new AddressService();stubProperties = new StubPropertiesManager();instance.setPropertiesManager(stubProperties);}@Testpublic void testAddressSiteProperties_AddressServiceDisabled() {/* Set up the AddressDAO Stubb for this test */Address address = new Address(1, "15 My Street", "My Town", "POSTCODE","My Country");addressDao = new StubAddressDao(address);instance.setAddressDao(addressDao);stubProperties.setProperty("address.enabled", "false");Address expected = Address.INVALID_ADDRESS;Address result = instance.findAddress(1);assertEquals(expected, result);}@Testpublic void testAddressSiteProperties_AddressServiceEnabled() {/* Set up the AddressDAO Stubb for this test */Address address = new Address(1, "15 My Street", "My Town", "POSTCODE","My Country");addressDao = new StubAddressDao(address);instance.setAddressDao(addressDao);stubProperties.setProperty("address.enabled", "true");Address result = instance.findAddress(1);assertEquals(address, result);}
}

所有这些都是很笨拙的,但是如果您不能提取接口会发生什么呢? 我将其保存另一天...

参考: Captain Debug博客上的 JCG合作伙伴 Roger Hughes提供的用于遗留代码的存根-测试技术6

相关文章 :

  • 测试技巧–不编写测试
  • 端到端测试的滥用–测试技术2
  • 您应该对什么进行单元测试? –测试技术3
  • 常规单元测试和存根–测​​试技术4
  • 使用模拟的单元测试–测试技术5
  • 有关为旧版代码创建存根的更多信息–测试技术7
  • 为什么要编写单元测试–测试技巧8
  • 一些定义–测试技术9
  • 使用FindBugs产生更少的错误代码
  • 在云中开发和测试

翻译自: https://www.javacodegeeks.com/2011/11/creating-stubs-for-legacy-code-testing.html

为旧版代码创建存根–测试技术6相关推荐

  1. 存根类 测试代码 java_为旧版代码创建存根-测试技术6

    存根类 测试代码 java 任何阅读此博客的人都可能已经意识到,目前我正在开发一个项目,其中包含大量的旧代码,这些旧代码庞大,扩展且编写时从未进行过任何测试. 在使用此遗留代码时,有一个行为非常差的类 ...

  2. 存根类 测试代码 java_有关为旧版代码创建存根的更多信息–测试技术7

    存根类 测试代码 java 在我的上一个博客中 ,我谈到了如何处理行为不佳的不可测试的 (1) SitePropertiesManager 类,以及如何通过提取接口来创建存根. 但是,如果由于旧类的源 ...

  3. 有关为旧版代码创建存根的更多信息–测试技术7

    在上一个博客中 ,我谈到了如何处理行为不佳的不可测试的 (1) SitePropertiesManager 类,以及如何通过提取接口来创建存根. 但是,如果由于旧类的源代码已被锁定在第三方JAR文件中 ...

  4. 癌症新知和癌症真相的区别_旧版代码是癌症

    癌症新知和癌症真相的区别 It's far too often that I see people shying away from newest technologies in the spirit ...

  5. 《Kali Linux高级渗透测试原书第2版》网络渗透测试技术书 无线网络渗透测试详解 黑客攻击与防范实战从入门到精通书

    内容简介: KaliLinux面向专业的渗透测试和审计,集成了大量挑选的检测工具.本书在KaliLinux平台上从一个攻击者的角度来审视网络框架,详细介绍了攻击者"杀链"采取的具体 ...

  6. 端到端测试_端到端测试的滥用–测试技术2

    端到端测试 我的上一个博客是有关测试代码方法的一系列博客中的第一篇,概述了使用一种非常常见的模式从数据库检索地址的简单方案: -并描述了一种非常通用的测试技术: 不编写测试 , 而是手动进行所有操作. ...

  7. 9针串口定义测试方法_一些定义–测试技术9

    9针串口定义测试方法 我认为我即将结束有关测试技术的博客系列,感觉好像已经过去了. 对我来说更清楚的一件事是,测试方法仍处于起步阶段,因此是开发人员之间争执或讨论的明确来源,这是一件好事. 我怀疑我们 ...

  8. 您应该对什么进行单元测试? –测试技术3

    昨天我在办公室里,和我的一位同事谈论测试,他对编写单元测试有些不服气. 他使用的原因之一是有些测试似乎毫无意义,这使我想到了什么是单元测试,什么也不需要打扰. 考虑下面一个简单的不可变的Name Be ...

  9. 端到端测试的滥用–测试技术2

    我的上一个博客是有关测试代码方法的一系列博客中的第一篇,概述了使用一种非常常见的模式从数据库检索地址的简单方案: -并描述了一种非常通用的测试技术: 不编写测试 , 而是手动进行所有操作. 今天的博客 ...

最新文章

  1. 基于Live555的多路视频流的流媒体服务器框架
  2. 每天一道LeetCode-----生命游戏
  3. 怎样使用Eclipse来开发Android源码
  4. linux 中w和x 区别,r、w、x权限在文件和目录中的含义有何区别?
  5. SEO之基础篇(一)
  6. 利用Java制作背单词小应用
  7. mac系统下为emacs设置中文字体,解决乱码问题
  8. PagerAdapter跟BaseAdapter的覆盖
  9. Vue-cli下打包资源相对路径踩坑
  10. DL-C1-week3-1(build a neural network with one hidden layer)多层感知机的简单实现
  11. 禁止edge浏览器自动更新
  12. 常用的机械3D设计软件大全
  13. 1+X计算机视觉考证一些知识点
  14. moses binarize-all问题
  15. Google软件测试之道(读书笔记)
  16. flex布局的应用 —— 模仿携程移动端的首页
  17. 计算机网络体系结构 - 网络安全
  18. 新手选车系列之(五): 手动挡还是自动挡
  19. OpenCV-python利用蒙版进行叠加(含alpha通道)
  20. DevStream 概览——开源 DevOps 工具链管理工具

热门文章

  1. java泛型程序设计——注意擦除后的冲突
  2. JavaWeb项目:简易小米商城系统
  3. 如何用for循环出数据库的数据
  4. 如何将网页部署到maven_如何通过Rultor将Maven工件部署到CloudRepo
  5. java8多线程运行程序_线程,代码和数据–多线程Java程序实际运行的方式
  6. gatling的环境配置_将Gatling集成到Gradle构建中–了解SourceSet和配置
  7. spring nosql_使用Spring Security和NoSQL的Spring Boot
  8. 英文连词_连词我们…讨厌
  9. junit测试起名字规则_如何在JUnit 5中替换规则
  10. jgit_JGit身份验证说明