怎样编写测试类测试分支
例如,您可能更喜欢编写经典的单元测试,通过检查返回值来单独测试对象的行为。 您可能会喜欢经典存根或伪造的物品; 或者您可能喜欢使用模拟对象模拟角色,甚至使用模拟对象作为存根。 这个博客以及我接下来的几篇博客都采用了一种非常非常通用的设计模式,并研究了可以采用的不同测试方法。
我正在使用的设计模式显示在下面的UML图中,这是我以前使用过的,主要是因为它是如此普遍。 您可能不喜欢它-它的设计更像是“问不说”而不是“告诉不问”,但是它适合这个简单的演示。
在此示例中,上面的普遍模式将用于从数据库中检索和验证地址。 可以从我的GitHub存储库中获得的示例代码以一个简单的Spring MVC Webapp为起点,并使用一个小型MySQL数据库来存储地址,其原因无非是我已经在笔记本电脑上本地运行了服务器。
就测试而言,博客将集中于测试服务层组件AddressService:
@Component
public class AddressService {private static final Logger logger = LoggerFactory.getLogger(AddressService.class);private AddressDao addressDao;/*** Given an id, retrieve an address. Apply phony business rules.* * @param id* The id of the address object.*/public Address findAddress(int id) {logger.info("In Address Service with id: " + id);Address address = addressDao.findAddress(id);businessMethod(address);logger.info("Leaving Address Service with id: " + id);return address;}private void businessMethod(Address address) {logger.info("in business method");// Do some jiggery-pokery here....}@Autowiredvoid setAddressDao(AddressDao addressDao) {this.addressDao = addressDao;}}
…如上面的代码所示,您可以看到非常简单:它具有findAddress(...)方法,该方法将单个地址的ID(或表主键)作为输入。 它调用数据访问对象(DAO),并假装在将Address对象返回给调用者之前进行一些业务处理。
public class Address {private final int id;private final String street;private final String town;private final String country;private final String postCode;public Address(int id, String street, String town, String postCode, String country) {this.id = id;this.street = street;this.town = town;this.postCode = postCode;this.country = country;}public int getId() {return id;}public String getStreet() {return street;}public String getTown() {return town;}public String getCountry() {return country;}public String getPostCode() {return postCode;}
}
如上所述,我将介绍测试此代码的不同策略,其中一些我保证您会讨厌。 第一个仍然被许多开发人员和组织广泛使用的是……
不要写任何测试
令人难以置信的是,某些人和组织仍在这样做。 他们编写代码,将其部署到Web服务器并打开一个页面。 如果页面打开,则他们将发送代码;如果页面未打开,则他们将修复代码,对其进行编译,然后重新部署,重新加载Web浏览器并重新测试。
我见过的关于该技术的最极端的例子:几年前,在一个著名的政府项目中,更改代码,部署到服务器,运行代码,发现错误并再次循环。 我猜想,为了节省资金,分包商从“离岸”业务中引入了一批廉价且缺乏经验的程序员,并且没有足够的经验丰富的程序员来指导他们。 所讨论的模块是一个基于Spring的简单消息驱动Bean,它从一个队列中获取消息,应用了一些业务逻辑,然后将其推入另一个队列:简单队列。 最初的作者首先编写了一些测试,然后将代码传递给其他经验不足的团队成员。 当代码更改并且测试失败时,他们只是关闭了所有测试。 测试包括将MDB部署到EJB容器(Weblogic),将消息推送到系统的前端,观察来自另一端的消息并调试整个过程中的日志。 您可能会说这样的端到端测试还不错,但是部署MDB和运行测试只花了一个小时:在一个工作日内,这是8个代码更改。 发展不完全Swift!
我的工作? 修复过程和代码。 解决方案? 编写测试,运行测试并重构代码。 该模块从零测试变成了大约40个单元测试和几个集成测试,并且经过改进并最终交付。 做完了
大多数人会对这种技术有自己的看法,而我的看法是:它产生了不可靠的代码; 使用此技术需要花费更长的时间编写和交付代码,因为您花费大量时间等待服务器启动,部署WAR / EJB等。并且,通常由经验不足的程序员或那些没有使用过此功能的程序员使用技术–您确实遭受了痛苦。 我可以说我从事的项目是编写测试的项目,而其他开发人员则不在。 测试团队在我的代码中发现的bug很少,而其他开发人员正在修复大量的bug,并疯狂地努力按时完成任务。 我是一个出色的程序员,还是编写测试能带来收益? 根据经验,如果您使用此技术,则将有很多其他错误要修复,因为您无法轻松且可重复地测试与您开发的故事相伴的多种场景。 这是因为它花费的时间太长,您必须记住每种情况,然后手动运行它们。
我确实想知道,不写测试技术是否是自1960年代以来的宿醉,当时计算时间非常昂贵,您必须手动在打Kong卡或纸带上编写程序,然后使用“真值表”进行目视检查。 当您对自己的代码工作感到满意后,便将其发送到计算机室并运行您的代码-我还不算老,无法记住60年代的计算。 机器时间昂贵的事实意味着自动化测试是不可能的。 尽管计算机的速度越来越快,但这种过时的范例仍在继续,逐渐退化为一种错误,您在其中错过了勤奋的精神检查,只执行了代码,如果代码破损,则您对其进行了修复。 这种退化的范式仍在学校,学院和书籍中教授,直到近几年才受到挑战。
这就是为什么很难说服人们改变他们的习惯吗?
这种技术的另一个主要问题是项目可能会陷入瘫痪状态。 就像我在上面说的那样,使用这种技术,您的错误数将很高,并且给项目经理带来不好的印象,使他们认为代码会发臭并强制执行以下想法:除非绝对必要,否则不要更改代码,因为这可能会破坏某些东西。 经理常常对授权代码更改不满意,他们通常对开发人员不信任,也不会对它们进行微管理。 确实,开发人员自己对添加代码更改非常犹豫,因为破坏某些内容会使它们看起来很糟糕。 他们所做的更改尽可能的小,并且没有任何重构。 随着时间的流逝,这会增加混乱,并且代码的退化甚至会变得更大。
虽然我认为您应该加载并查看页面以确保所有功能都正常运行,但只有在有大量测试告诉您代码可以正常工作时,才应该在故事的结尾进行操作。
我希望当我总结这种方法很糟糕的时候(尽管时间会证明一切)时,我不会引起争议。 您可能还想知道为什么要包含它,原因是要指出它很烂,并在下面的博客中提供了一些替代方法。
参考: 测试技术–第1部分–不通过Captain Debug博客从我们的JCG合作伙伴
编写测试 。相关文章 :
- 端到端测试的滥用–测试技术2
- 您应该对什么进行单元测试? –测试技术3
- 常规单元测试和存根–测试技术4
- 使用模拟的单元测试–测试技术5
- 为旧版代码创建存根-测试技术6
- 有关为旧版代码创建存根的更多信息–测试技术7
- 为什么要编写单元测试-测试技巧8
- 一些定义–测试技术9
- 使用FindBugs产生更少的错误代码
- 在云中开发和测试
翻译自: https://www.javacodegeeks.com/2011/11/testing-techniques-not-writing-tests.html
怎样编写测试类测试分支