答软件开发者面试百问 之 软件测试

发表于:2011-7-26 14:30

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

 作者:liangshi    来源:51Testing软件测试博客

  自InfoQ翻译了Jurgen Appelo的“软件开发者面试百问”,该文受到了许多读者的欢迎。在2009年5月刊的《程序员》中,周伟明先生对其中的“项目管理”和“软件测试”部分的题目进行了回答。笔者不才,也想试着给出自己的答案。既然是“面试”,那么作答时,便不参考其他资料,只凭记忆和经验撰写。

  1、什么是回归测试?怎样知道新引入的变化没有给现有的功能造成破坏?

  回归测试是指,运行一组测试用例(称作“回归测试用例集”)来检查代码的变化没有破坏已有的功能。软件开发是一个演进的过程,需要不停地重构和增加代码。回归测试提供了修改的正确性反馈,为稳定的开发流程提供了安全网。在理想的情况下,应该将所有测试用例组成回归测试用例集,来检查修改的正确性。不过,受到资源的限制,开发者往往选择与修改相关的测试用例来运行回归测试。例如,被修改类的所有单元测试用例、被修改模块的所有组件测试用例、被修改系统的所有功能性测试用例等。

  在我的工作中,我通过以下方法来检查代码变化的正确性。

  ● 利用每小时一次的rolling test来检查最近的签入(check-in)没有造成构建失败(build break)、部署失败、端到端系统测试(end-to-end system test)失败。这可以及时地发现阻碍每日测试的blocking bug。

  ● 利用每日测试(daily test)来运行所有的自动化测试用例集。

  ● 通过代码比较工具,检查前后版本的代码。一方面,通过代码检查来挖掘可能的问题;另一方面,可以有针对性地补充一些测试用例,以覆盖新的逻辑。

  ● 在恰当的时候,再次运行手工测试用例集。由于我的测试用例集的自动化程度较高,我通常在里程碑(milestone)快结束前运行手工测试用例集。

  ● 代码变更往往造成测试失败(test break),需要重构测试代码来适应新的接口和实现。采用良好的测试实现模式,可以降低测试维护的代价。

  2、如果业务层和数据层之间有依赖关系,你该怎么写单元测试?

  严格地说,单元测试不应该访问外部资源(包括文件、网络、数据库等)。单元测试的目的是提供快速的正确性反馈,使“测试—开发—重构”的迭代循环达到“流”状态。依赖于外部资源的单元测试运行缓慢,可能给开发带来负面影响。如果测试运行超过1分钟,许多时间被浪费在等待上,开发者很难到达“流”状态,开发效率会隐式地降低。如果测试运行超过5分钟,开发者可能会选择偶尔运行单元测试,以加速开发速度。这将大大削弱单元测试作为安全网的效果,进一步降低开发效率。

  如果业务层和数据层有依赖关系,开发者还是应该尽量使单元测试不访问外部资源。我会使用以下策略来达到这一目标。

  1)在设计上,将业务层和数据层的依赖限制在最小范围内。一个可能的方案是,将依赖封装在一个类中,例如DataManager。在业务层,只有少量代码依赖于它,而大多数代码不依赖于数据层。对于数据层无关的业务层代码,可以方便地编写单元测试。

  2)对于依赖于DataManager的类,可以采用伪对象(mock object)测试模式来编写单元测试。对于C#等静态语言,需要使用提取借口(extract interface)的重构手法,获得DataManager的接口IDataManager。然后编写符合该接口的伪对象,例如DataManagerMock。DataManagerMock不访问数据库,它使用内存中的数据来模拟数据层操作。测试方法用依赖注入(dependence injection)策略,使被测试的业务对象依赖于受控的DataManagerMock,这样就可以编写只访问内存对象的单元测试了。以下代码演示了这种方法的思路。

1:// Business class under test
2:classEmployee {
3:     IDataManager data;
4:     Business(IDataManager data) {
5:this.data = data;
6:     }
7:     ...
8: }
9:
10:// Mock object
11:classDataManagerMock : IDataManager {
12:// database in memory
13:     Hashtable employees =newHashtable();
14:     ...
15: }
16:
17: [TestMethod]
18:voidTestEmployee() {
19:// setup
20:     IDataManager data =newDataManagerMock();
21:     Employee e = Employee(data);
22:// test object e with data
23:     ...
24: }

  3)除了伪对象,还可以采用测试专用子类(test specific subclass)、依赖注册与查找(dependence register and lookup)、动态类型(duck typing)等策略,使业务对象在测试方法中不依赖于DataManager,而是依赖于不访问数据库的伪数据层对象。这里的关键是,解除业务层与数据层的依赖,在测试方法中,将数据层对象替换为测试专用对象(test specific object)。

  4)有时,访问数据库是难以避免的。在这种情况下,应该为每一位开发者和测试者建立数据库沙箱(sand-box),使得他们的工作相互独立。在测试方法中,先用数据操作脚本将数据库恢复到指定状态,然后再执行测试逻辑。通常,我会从产品数据库中选择少量数据,构成一个典型的数据集,用于初始化数据库。这样既体现了产品数据库的特性,也尽可能地提高了测试速度。

41/41234>
《2023软件测试行业现状调查报告》独家发布~

精彩评论

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号