一起学习
【译者注】本文译自JUnit3.8.1发布版本中JUnit A Cook's Tour一文。
1.简介
在一篇早些的文章(请参见Test Infected: Programmers Love Writing Tests, Java Report, July 1998, Volume 3, Number 7)中,我们描述了如何使用一个简单的框架来编写可重复的测试。在本文中我们将匆匆一瞥其内中细节,并向你展示该框架本身是如何被构造的。
我们细致地研究JUint框架并思索如何来构造它。我们发现了许多不同层次上的教训。在本文中,我们将尝试着立刻与它们进行沟通,这是一个令人绝望的任务,但至少它是在我们向你展示设计和构造一件价值被证实的软件的上下文中来进行的。
我们引发了一个关于框架目标的讨论。在对框架本身的表达期间,目标将重复出现许多小的细节中。此后,我们提出框架的设计和实现。设计将从模式(惊奇,惊奇)的角度进行描述,并作为优美的程序来予以实现。我们总结了一些优秀的关于框架开发的想法。
2.什么是JUnit的目标呢?
首先,我们不得不回到开发的假定上去。如果缺少一个程序特性的自动测试(automated test),我们便假定其无法工作。这看起来要比主流的假定更加安全,主流的假定认为如果开发者向我们保证一个程序特性能够工作,那么现在和将来其都会永远工作。
从这个观点来看,当开发者编写和调试代码时,它们的工作并没有完成,它们还要必须编写测试来演示程序能够工作。然而,每个人都太忙,他们要做的事情太多,他们没有充足的时间用于测试。我已经有太多的代码需要编写,要我如何再来编写测试代码?回答我,强硬的项目经理先生。因此,首要目标就是编写一个框架,在这个框架中开发者能够看到实际来编写测试的希望之光。该框架必须要使用常见的工具,从而学习起来不会有太多的新东西。其不能比完全编写一个新测试所必须的工作更多。必须排除重复性的工作。
如果所有测试都这样去做的话,你将可以仅在一个调试器中编写表达式来完成。然而,这对于测试而言尚不充分。告诉我你的程序现在能够工作,对我而言并没有什么帮助,因为它并没有向我保证你的程序从我现在集成之后的每一分钟都将会工作,以及它并没有向我保证你的程序将依然能够工作五年,那时你已经离开了很长的时间。
于是,测试的第二个目标就是生成可持续保持其价值的测试。除原作者以外的其他人必须能够执行测试并解释其结果。应该能够将不同作者的测试结合起来并在一起运行,而不必担心相互冲突。
最后,必须能够以现有的测试作为支点来生成新的测试。生成一个装置(setup)或夹具(fixture)是昂贵的,并且一个框架必须能够对夹具进行重用,以运行不同的测试。哦,还有别的吗?
3.JUnit的设计
JUnit的设计将以一种首次在Patterns Generate Architectures(请参见"Patterns Generate Architectures", Kent Beck and Ralph Johnson, ECOOP 94)中使用的风格来呈现。其思想是通过从零开始来应用模式,然后一个接一个,直至你获得系统架构的方式来讲解一个系统的设计。我们将提出需要解决的架构问题,总结用来解决问题的模式,然后展示如何将模式应用于JUnit。
3.1 由此开始-TestCase
首先我们必须构建一个对象来表达我们的基本概念,TestCase(测试案例)。开发者经常在头脑中存在着测试案例,但在实现它们的时候却采用了许多不同的方式-
n 打印语句
n 调试器表达式
n 测试脚本
如果我们想要轻松地操纵测试,就必须将它们构建成对象。这将会获取到一个仅仅是隐藏在开发者头脑中的测试,并使之具体化,其支持我们创建测试的目标,即能够持续地保持它们的价值。同时,对象的开发者比较习惯于使用对象来进行开发,因此将测试构建成对象的决定支持我们的目标-使测试的编写更加吸引人(或至少是不太华丽)。
Command(命令)模式(请参见Gamma, E., et al. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, Reading, MA, 1995)则能够比较好地满足我们的需求。摘引其意图(intent),“将一个请求封装成一个对象,从而使你可用不同的请求对客户进行参数化;对请求进行排队或记录请求日志...”Command告诉我们可以为一个操作生成一个对象并给出它的一个“execute(执行)”方法。以下代码定义了TestCase类:
public abstract class TestCase implements Test {
…
}
因为我们期望可以通过继承来对该类进行重用,我们将其声明为“public abstract”。暂时忽略其实现接口Test的事实。鉴于当前设计的需要,你可以将TestCase看作是一个孤立的类。
每一个TestCase在创建时都要有一个名称,因此若一个测试失败了,你便可识别出失败的是哪个测试。
public abstract class TestCase implements Test {
private final String fName;
public TestCase(String name) {
fName= name;
}
public abstract void run();
…
}
为了阐述JUnit的演变过程,我们将使用图(diagram)来展示构架的快照(snapshot)。我们使用的标记很简单。其使用包含相关模式的尖方框来标注类。当类在模式中的角色(role)显而易见时,则仅显示模式的名称。如果角色并不清晰,则在尖方框中增加与该类相关的参与者的名称。该标记可使图的混乱度降到最小限度,并首次见诸于Applying Design Patterns in Java(请参见Gamma, E., Applying Design Patterns in Java, in Java Gems, SIGS Reference Library, 1997)。图1展示了这种应用于TestCase中的标记。由于我们是在处理一个单独的类并且没有不明确的地方,因此仅显示模式的名称。
图1 TestCase应用Command
下载本文示例代码
JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇JUnit之走马观花篇
阅读(173) | 评论(0) | 转发(0) |