• 软件测试技术
  • 软件测试博客
  • 软件测试视频
  • 开源软件测试技术
  • 软件测试论坛
  • 软件测试沙龙
  • 软件测试资料下载
  • 软件测试杂志
  • 软件测试人才招聘
    暂时没有公告

字号: | 推荐给好友 上一篇 | 下一篇

用模仿对象替换合作者以改进单元测试

发布: 2008-7-30 09:55 | 作者: Alexander Day Chaffe | 来源: IBM | 查看: 71次 | 进入软件测试论坛讨论

领测软件测试网

重构由许多小的技术性步骤组成。这些步骤统称为 技巧。如果您象按照食谱那样严格遵循这些技术, 那么您在学习重构时应该没有太大的麻烦。

  1. 标识创建或获取合作者的代码的所有出现。
  2. 抽取方法重构应用于这个创建代码,创建工厂方法(在 Fowler 书籍的第 110 页中讨论;有关更多信息,请参阅 参考资料一节)。
  3. 确保目标对象及其子类可以访问工厂方法。(在 Java 语言中,使用 protected 关键字)。
  4. 在测试代码中,创建模仿对象且实现与合作者相同的接口。
  5. 在测试代码中,创建扩展(专用于)目标对象的特殊化对象。
  6. 在特殊化对象中,覆盖创建方法以返回为测试提供的模仿对象。
  7. 可选的:创建单元测试以确保原始目标对象的工厂方法仍返回正确的非模仿对象。

示例:ATM

设想您正在编写用于银行自动柜员机(Automatic Teller Machine)的测试。其中一个测试可能类似于清单 2:


清单 2. 初始单元测试,在模仿对象引入之前
 public void testCheckingWithdrawal() {
float startingBalance = balanceForTestCheckingAccount();
AtmGui atm = new AtmGui();
insertCardAndInputPin(atm);
atm.pressButton("Withdraw");
atm.pressButton("Checking");
atm.pressButtons("1", "0", "0", "0", "0");
assertContains("$100.00", atm.getDisplayContents());
atm.pressButton("Continue");
assertEquals(startingBalance - 100,
balanceForTestCheckingAccount());
}

另外, AtmGui 类内部的匹配代码可能类似于清单 3:


清单 3. 产品代码,在重构之前
 private Status doWithdrawal(Account account, float amount) {
Transaction transaction = new Transaction();
transaction.setSourceAccount(account);
transaction.setDestAccount(myCashAccount());
transaction.setAmount(amount);
transaction.process();
if (transaction.successful()) {
dispense(amount);
}
return transaction.getStatus();
}

该方法将起作用,遗憾的是,它有一个副作用:支票帐户余额比测试开始时少,这使得其它测试变得更困难。 有一些解决这种困难的方法,但它们都会增加测试的复杂性。 更糟的是,该方法还需要对管理货币的系统进行三次往返。

要修正这个问题,第一步是重构 AtmGui 以允许我们用模仿事务替换实际事务, 如清单 4 中所示(比较 粗体的源代码以查看我们正在更改什么):


清单 4. 重构 AtmGui
 private Status doWithdrawal(Account account, float amount) {
Transaction transaction = createTransaction();
transaction.setSourceAccount(account);
transaction.setDestAccount(myCashAccount());
transaction.setAmount(amount);
transaction.process();
if (transaction.successful()) {
dispense(amount);
}
return transaction.getStatus();
}
protected Transaction createTransaction() {
return new Transaction();
}

后退到测试类内部,我们将 MockTransaction 类定义为成员类,如清单 5 中所示:


清单 5. 将 MockTransaction 定义为成员类
 private MockTransaction extends Transaction {
private boolean processCalled = false;
// override process method so that no real work is done
public void process() {
processCalled = true;
setStatus(Status.SUCCESS);
}
public void validate() {
assertTrue(processCalled);
}
}

最后,我们可以重写测试,以便被测试的对象使用 MockTransaction 类,而不是使用实际类,如清单 6 中所示:


文章来源于领测软件测试网 https://www.ltesting.net/

32/3<123>

关于领测软件测试网 | 领测软件测试网合作伙伴 | 广告服务 | 投稿指南 | 联系我们 | 网站地图 | 友情链接
版权所有(C) 2003-2010 TestAge(领测软件测试网)|领测国际科技(北京)有限公司|软件测试工程师培训网 All Rights Reserved
北京市海淀区中关村南大街9号北京理工科技大厦1402室 京ICP备2023014753号-2
技术支持和业务联系:info@testage.com.cn 电话:010-51297073

软件测试 | 领测国际ISTQBISTQB官网TMMiTMMi认证国际软件测试工程师认证领测软件测试网