软件测试中如何提取一个测试层次结构
测试用例(Test Case)是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。
测试用例(Test Case)目前没有经典的定义。比较通常的说法是:指对一项特定的软件产品进行测试任务的描述,体现测试方案、方法、技术和策略。内容包括测试目标、测试环境、输入数据、测试步骤、预期结果、测试脚本等,并形成文档。
不同类别的软件,测试用例是不同的。不同于诸如系统、工具、控制、游戏软件,管理软件的用户需求更加不统一,变化更大、更快。笔者主要从事企业管理软件的测试。因此我们的做法是把测试数据和测试脚本从测试用例中划分出来。测试用例更趋于是针对软件产品的功能、业务规则和业务处理所设计的测试方案。对软件的每个特定功能或运行操作路径的测试构成了一个个测试用例。
随着中国软件业的日益壮大和逐步走向成熟,软件测试也在不断发展。从最初的由软件编程人员兼职测试到软件公司组建独立专职测试部门。测试工作也从简单测试演变为包括:编制测试计划、编写测试用例、准备测试数据、编写测试脚本、实施测试、测试评估等多项内容的正规测试。测试方式则由单纯手工测试发展为手工、自动兼之,并有向第三方专业测试公司发展的趋势。
要使最终用户对软件感到满意,最有力的举措就是对最终用户的期望加以明确阐述,以便对这些期望进行核实并确认其有效性。测试用例反映了要核实的需求。然而,核实这些需求可能通过不同的方式并由不同的测试员来实施。例如,执行软件以便验证它的功能和性能,这项操作可能由某个测试员采用自动测试技术来实现;计算机系统的关机步骤可通过手工测试和观察来完成;不过,市场占有率和销售数据(以及产品需求),只能通过评测产品和竞争销售数据来完成。
既然可能无法(或不必负责)核实所有的需求,那么是否能为测试挑选最适合或最关键的需求则关系到项目的成败。选中要核实的需求将是对成本、风险和对该需求进行核实的必要性这三者权衡考虑的结果。
确定测试用例之所以很重要,原因有以下几方面。
测试用例构成了设计和制定测试过程的基础。 测试的“深度”与测试用例的数量成比例。由于每个测试用例反映不同的场景、条件或经由产品的事件流,因而,随着测试用例数量的增加,您对产品质量和测试流程也就越有信心。 判断测试是否完全的一个主要评测方法是基于需求的覆盖,而这又是以确定、实施和/或执行的测试用例的数量为依据的。类似下面这样的说明:“95 % 的关键测试用例已得以执行和验证”,远比“我们已完成 95 % 的测试”更有意义。 测试工作量与测试用例的数量成比例。根据全面且细化的测试用例,可以更准确地估计测试周期各连续阶段的时间安排。 测试设计和开发的类型以及所需的资源主要都受控于测试用例。 测试用例通常根据它们所关联关系的测试类型或测试需求来分类,而且将随类型和需求进行相应地改变。最佳方案是为每个测试需求至少编制两个测试用例:
·一个测试用例用于证明该需求已经满足,通常称作正面测试用例;
·另一个测试用例反映某个无法接受、反常或意外的条件或数据,用于论证只有在所需条件下才能够满足该需求,这个测试用例称作负面测试用例。
情景:
这个问题在编写客户端或端到端测试的时候尤为常见——就是那些为整个系统而不是为某个类所做的测试。偶尔Junit用户——那些几乎完全依赖 JUnit作为测试驱动的开发工具的人——会忘记那些从来不使用Junit的、非测试驱动程序员,因为JUnit提供了一个易于使用的Java框架来编写测试程序。说这些是因为一个测试驱动的程序员会说:“如果你有一个这么大的测试模块,那你的测试代码就太大了,必须要修改测试代码使其只专注于系统的一个方面。如果你这样做了,那问题就会得到解决”。其实说的没错,可是这话是典型的数学家的语言:专注,精确,然而毫无用处。
如果能够精简测试模块或者能够找出其中没有被所有测试所共享的部分,那就更好了:我们更喜欢简单的测试用例层次结构。如果已经无法将事情简化——或者是看不出该如何做--那也至少应该试着将通用的测试模块移到一个地方。
技巧:
解决这个问题的技巧说来很简单:尽管编写的是测试程序,但它们还是用方法和对象实现的,所以将其当作方法和对象来看待。一个从一组类中抽取重复行为的办法是,应用抽取超类的重构方法创建一个类层次结构。具体步骤如下:
1. 选择两个有通用测试模块的测试用例类。
2. 创建一个新的TestCase的子类,它是有重复的测试模块的测试用例类的超类。在这里,我们将这个新类叫做BaseFixture,这个是各人自己取的。
3. 将BaseFixture类声明为抽象类,没有必要创建这个类的实例。
4. 修改测试用例类代码,使其继承自BaseFixture而不是直接继承TestCase。
5. 将重复的测试模块复制到BaseFixture中——就是说,复制参数域和setUp()方法中初始化参数域的代码。可能需要修改参数域,将其声明成受保护的而不是私有的,否则测试用例类就不能使用它们。可以将参数域封装在一个受保护的get方法里面,但是在这个例子中我们觉得没必要这样做。
6. 从每一个测试用例类中删除测试模块参数域,从setUp()方法中删除已经移到BaseFixture中的代码。
7. 在每个测试用例类的setUp()方法的开始加上一行super.setUp()。
8. 现在可以重新编译运行此测试程序,来验证其行为并没有改变。可以对尽可能多的共享通过测试模块对象的测试用例类重复上述步骤。
另外在验证了做完上述步骤没有带来任何问题以后,要看看那些setUp()方法中是否可以删除一些空的或只有一行super.setUp()的方法。
讨论:
可以将这个诀窍归结为:“抽取测试用例类的超类,将其声明为抽象的因为没有理由去实例化它。”
1. 通过将重复的测试代码移到一个超类中来消除重复性事一个好主意。
2. 在重复代码出现之前,我们一般想不到它。
最后有个地方要注意:必要的时候调用方法super.setUp()和super.tearDown()。从TestCase类直接派生子类的时候,并不需要担心这些,因为超类的实现中什么也没有做;但是现在你的超类的每个方法的实现中都可能有很重要的部分。这是一个常犯的错误——一个我们所有人都会犯的错误,并将持续到我们的编程生涯的结束的那一天——所以不必为此感到难过。
文章来源于领测软件测试网 https://www.ltesting.net/