如何将其分解为单元测试?

时间:2009-04-20 08:32:19

标签: unit-testing refactoring

我有一个在对象上调用的方法来执行一些业务逻辑并将其添加到数据库中。

对象是一个事务,业务逻辑的一部分需要在数据库中搜索帐户上的相关帐户和历史记录项。

然后有一系列的比较和操作需要从帐户中恢复信息并将其应用于事务,然后将事务传递给其他人并写入数据库。

我目前唯一可以考虑测试的方法是在测试中创建一个帐户和相关的历史信息,然后为每个不同的场景构建一个事务,并捕获写入数据库的信息以获取交易和信息被传递,但这在一次测试中感觉就像它的测试方式太多了。每个场景都将在一个单独的单元测试中执行,测试结构被重构为单独的方法,但测试所针对的实际代码段超过500行。

我想这个问题更多的是关于重构而不是单元测试,但在这种情况下它们是齐头并进的。

如果有人有任何建议(好的或坏的),那么我很高兴听到它。

编辑:

伪代码:

Find account for transaction 
Do validation on transaction codes and values 
Update transaction with info from account 
Get related history from account Handle different transaction codes and values (6 different combinations, each with different logic) 
Update the transaction again with new account info (resulting from business logic) 
Send transaction to clients

4 个答案:

答案 0 :(得分:4)

如果你在这个问题上有一些伪代码,我会很感激,但只要遵循它我就会:

  • 为直接访问数据库的数据访问对象创建接口 - 这样您就可以传入一个只会假装(例如,模拟)它访问数据库的对象。然后,此对象将返回与数据库将返回的结果一致的结果,而不实际执行任何数据库调用。您的对象还可以模拟诸如将数据回滚到其原始状态之类的场景。
  • 将每个“场景”提取为一个单独的方法 - 这是一个单元的本质。如果你的方法是500行,那么必须有可以提取的连续块。如果合适,为每个编写一个单元测试。
  • 如果您的单元测试测试太多,这可能意味着您的方法做得太多 - 您可以通过识别您正在测试的不同内容然后将它们放入自己的方法中来提取方法。冲洗并重复,直到每种方法只需要一次测试。
  • 交易“传递给其他人”听起来像一个代码味道 - 一个交易本身应该只是一个连续的单位。如果您需要不同的用户来完成交易,那么您做得太多了;在数据库中跟踪数据的状态,而不是在标记等方面,而不是在数据库事务方面。

答案 1 :(得分:1)

将单元与现有遗留代码分开可能非常棘手且耗时。查看Working Effectively With Legacy Code以获取各种经过验证的测试技术,以使事情更易于管理。

答案 2 :(得分:0)

这取决于您想要测试的内容。您想测试数据库事务吗?您想测试商业交易还是其他什么?尝试使用模型来处理您不想测试的内容。使用模型,您可以专注于某些测试目标。

答案 3 :(得分:0)

是的你 - 可以 - 重写你当前的代码,以便它可以进行单元测试 所有指南和最佳实践。

但是,这可能很昂贵,您应该估算成本并进行比较 反对收入...

收入是您可能会发现代码存在问题,如果做得正确,则会因重构而降低复杂性。

这两个因素可能会节省一些时间 - 将来。

成本是您花费时间和精力重构代码, 编写测试用例以及将来可能需要花费的额外时间 维护测试用例和模拟代码 - 这可能是很大的成本。

您正在将已知成本与未来风险进行比较,我相信很多聪明人都知道如何做到这一点,但很明显,您实际上可以花费无限时间进行重构和嘲弄,而不会降低失败的风险。如果代码和问题很复杂并且你在重构时搞砸了,那么零(或者甚至根本没有),所以你需要在这里找到平衡。

在这种情况下,由于代码是旧的,可​​能可以“草率”或“实用”并进行黑盒测试 - 或自上而下的测试,只需测试界面(或抽象)而不必费心去模拟数据库。是的,您可以说这不是单元测试,而是系统测试或功能测试实践。

...但是,它可能会为您的资金 - 或您的雇主/客户的资金 - 提供最佳价值 - 或者与您的重要其他人(或者至少有更多时间观看发现渠道)的时间更长。

如果您有旧代码,允许黑盒测试,允许测试之间的依赖关系并编译一系列测试来设置测试数据并对其进行操作,并且至少在100%测试时自动测试。