您如何为依赖无法模仿的具体外部实现的代码编写测试?


17

背景:我正在考虑通过为我一直在研究的模块创建一些单元测试的概念来向同事介绍单元测试的概念。它的要求最近发生了变化,并且需要更多的抽象/交互,因此,这似乎是开发一套测试套件的好方法,该套件可以“证明”它的工作原理,而无需手动在应用程序周围戳戳。

但是,问题在于该模块依赖于不可模拟的外部因素,即PDF和XSL。基本上,我从数据库中读取XML并对其进行XSL转换,然后使用称为ABCPDF的库将其转换为PDF。然后将此PDF与基于静态模板的另一个PDF合并。我知道我可以测试XML并确保值正确,但是许多潜在的错误和问题都与最终文档的实际显示有关-例如,细节,例如包裹了多长的文本字符串,某些HTML区域位于甚至可以测试这些东西(我意识到这些可能是集成测试,或者..我忘记了其名称的第三种测试[不是验收测试,另一种]而不是单元 测试),因为据我所知,我无法轻松地模拟出一个PDF,除非创建它,然后回读或创建一个HTML字符串(即转换后的XML),然后手工解析它以检查其中是否存在某些表格单元格与其他表格单元的关系。

在这种情况下,我应该只专注于单元测试以确保信息正确,并且可以创建 PDF或合并它们,或者采取其他任何措施来针对实际的显示问题进行手动测试吗?


6
“不可模仿的外部因素”提示您首先没有进行单元测试。这意味着集成测试。你想做什么?您的代码的单元测试或此复合对象的集成测试?请选择一个,因为很难同时讨论两者。
S.Lott

2
我买的不是“不可嘲笑的”。我会接受“我不知道如何嘲笑”,这仅表示您真正的问题是“我如何嘲笑它”。
Rein Henrichs

大概:)我熟悉模拟所用的XML,但不熟悉在格式很重要的情况下如何模拟实际的PDF或HTML文档。
韦恩·莫利纳

1
我认为您的意思是“功能”(应用程序端到端)或“系统”(多个应用程序端到端)测试
Gary Rowe

@Gary-是的,功能就是这个词。我现在通过学习Rails来记住它们:单元测试模型,功能测试控制器,集成测试一切。
韦恩·莫利纳

Answers:


13

测试功能而不是单元

使用已知的xml输入,输出PDF并手动(并谨慎)验证其正确性。然后将其保存为参考。

将来使用相同xml输入的测试可以将二进制文件与参考进行比较。

如果文件级比较不令人满意,请在测试结束时显示PDF并截取屏幕截图,然后将自动测试与参考屏幕截图进行比较。


+1,因为您只对此级别的最终结果感兴趣。如果您更改获取PDF的实现方式,则不必更改功能测试。
加里·罗

2
+1是个好建议,这是我们在当前项目中所做的。我们构建了一个用于进行PDF比较的自定义工具集,该工具集使我们可以省略文档中的变化部分,例如时间戳。注意事项:切换到其他PDF渲染器(版本)可能会导致版面中的细微变化,从而导致与误报的信号堆进行直接二进制比较。
彼得Török

5

通常,在这种情况下,您将无法测试的所有内容抽象到可以与接口一起使用的实现背后。我会做一些愚蠢的事情,例如PDF builder,因为这看起来很合理。

public class PdfBuilder : IPdfBuilder
{
  public byte[] BuildPdf(...)
  {
    // actual untestable code here
  }
}

public interface IPdfBuilder
{
  byte[] BuildPdf(...);
}

然后,您可以在测试中模拟IPdfBuilder以执行所需的任何操作。这通常意味着您需要开始使用IoC容器(/programming/871405/why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code如果您现在不使用的话,请/programming/21288/which-net-dependency-injection-frameworks-are-worth-look-in作为开始的地方)。

不是单元测试的测试通常称为集成测试。复杂的集成测试通常并不完全值得,因此您只需将其抽象出来并减少该抽象中的业务逻辑量,即可在单元测试中对其进行测试。

让我知道这是否还不清楚。


+1用于隐藏无法测试的代码。然后,你可以做手工测试,直到你的工作有什么需要穿越该接口,以获得正确的结果,以及单元测试被正确地产生,让您回归单元测试。
Ethel Evans,

1

不久前,我建立了非常相似的东西,并且只使用了基本的视觉测试。测试不一定是自动化的,因此仅寻找预期的结果就没有任何错误(显然,在各种预定的情况下)。通常,一张图片值得一千次涉及视觉的测试。我广泛使用自动化的单元测试,但是我认为有些人在进行GUI测试或任何可视IMHO时可能会感到有些困惑。对于某些产品,我确实认识到这种“足够好”的方法还不够,所以YMMV。

但是,对于不可模仿的外部性,我会有些担心。这可能是紧密耦合的标志,通常可以避免这种情况,但是如果没有更多细节,我不会在这方面对您的代码进行过多推测。


这是非常紧密的耦合,但这是我无法解决的领域,因为没有可以使它松散耦合的买进,也没有用于重构的资源(但这是一整套完全不同的问题)。
韦恩·莫利纳
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.