How should I unit test a code-generator?我知道这是一个困难且开放性的问题,但是我想把它扔到地板上,看看是否有人有任何有趣的建议。 我已经开发了一个代码生成器,该代码生成器将python接口带到我们的C代码(通过SWIG生成),并生成将其公开为WebServices所需的代码。开发此代码时,我是使用TDD进行的,但是我发现自己的测试非常脆弱。因为每个测试本质上都是想验证给定的输入代码位(恰好是C头),所以我会得到给定的输出代码位,所以我编写了一个小型引擎,该引擎从XML输入文件中读取测试定义并生成来自这些期望的测试案例。 问题是我根本不敢修改代码。单元测试本身的事实和事实是:复杂:a,脆弱: 。 因此,我正在尝试解决该问题的替代方法,这让我感到很震惊,我可能正在以错误的方式解决它。也许我需要更多地关注结果,即IE:我生成的代码是否实际运行并按照我想要的方式运行,而不是代码看起来像我想要的方式。 有没有人愿意分享与之类似的经历? 我开始用自己的代码生成器编写经验总结,然后回过头来重新阅读您的问题,发现您自己已经碰到了相同的问题,专注于执行结果而不是代码布局/看。 问题是,这很难测试,生成的代码可能不适合在单元测试系统的环境中实际运行,并且如何编码预期的结果? 我发现您需要将代码生成器分解为更小的部分,并对它们进行单元测试。如果您问我,对完整代码生成器进行单元测试更像是集成测试,而不是单元测试。 回想一下,"单元测试"只是一种测试。您应该能够对代码生成器的内部部分进行单元测试。您真正在这里看到的是系统级别的测试(也称为回归测试)。这不仅是语义……还有不同的思维方式,方法,期望等。当然还有更多工作要做,但是您可能需要硬着头皮,建立一个端到端的回归测试套件:固定的C文件-> SWIG接口-> python模块->已知输出。您确实想对照预期的输出(最终的Python程序产生的结果)检查已知的输入(固定的C代码)。直接检查代码生成器的结果就像比较目标文件... 我发现您需要比正在生成的东西更多地测试正在生成的东西。 就我而言,该程序生成许多类型的代码(C#,HTML,SCSS,JS等),这些代码可编译为Web应用程序。我发现减少总体回归错误的最好方法是测试Web应用程序本身,而不是测试生成器。 不要误会我的意思,仍然有单元测试签出了一些生成器代码,但是我们最大的好处就是对生成的应用程序本身进行了UI测试。 因为我们正在生成它,所以我们还在JS中生成了一个不错的抽象,我们可以用它来对应用程序进行编程测试。我们遵循了此处概述的一些想法:http://code.tutsplus.com/articles/maintainable-automated-ui-tests--net-35089 最重要的是,它真正地端到端地测试了系统,从代码生成到实际生成。一旦测试失败,可以很容易地将其追溯到发电机损坏的地方。 非常甜美。 祝你好运! 我的建议是找出一组已知的输入输出结果,例如已经存在的一些简单案例,并对所产生的代码进行单元测试。完全有可能,当您更改生成器时,所生成的确切字符串可能会稍有不同……但是您真正关心的是,是否以相同的方式解释它。因此,如果您测试结果就像测试该代码是否是您的功能,您将发现它是否以您想要的方式成功。 基本上,您真正想知道的是,如果不对每个可能的组合进行物理测试(也:不可能),生成器是否会产生您期望的结果。通过确保生成器与您期望的方式保持一致,您可以更好地感到生成器将在越来越复杂的情况下成功。 通过这种方式,您还可以建立一套回归测试(需要保持正常工作的单元测试)。这将帮助您确保对生成器所做的更改不会破坏其他形式的代码。当遇到单元测试未捕获的错误时,您可能希望将其包括在内以防止类似的损坏。 单元测试只是测试特定的单元。因此,如果您正在编写有关类A的规范,则理想的情况是类A没有类B和C的真实具体版本。 好吧,我后来发现这个问题的标签包括C / Python,但是原理是相同的:
由于上述系统A向系统B和C注入了接口,因此您可以仅对系统A进行单元测试,而无需其他任何系统执行实际功能。这是单元测试。 这是一种从创建到完成都接近系统的聪明方法,每种行为都有不同的When规范:
因此,总而言之,单个单元/规范可以具有多种行为,并且随着开发单元/系统的规范不断增长。如果被测系统依赖于其中的其他具体系统,请当心。 只是要指出,在验证结果的同时,您仍然可以实现细粒度的测试:您可以通过将单个代码块嵌套在一些设置和验证代码中来测试各个代码块:
假设您将生成的代码由较小的块组装而成,并且块不会频繁更改,则可以行使更多条件并进行更好的测试,并希望避免在更改一个块的详细信息时所有测试都中断。铅> 如果您正在* nux上运行,则可以考虑转储unittest框架,以使用bash脚本或makefile。在Windows上,您可以考虑构建一个运行生成器的shell应用程序/函数,然后使用该代码(作为另一个进程)并对该单元进行测试。 第三个选择是生成代码,然后从中构建仅包含单元测试的应用程序。同样,您将需要一个shell脚本或其他什么来为每个输入运行它。关于如何对预期行为进行编码,我发现可以使用与生成C接口几乎相同的方式来完成编码,只是使用生成的接口而不是C接口。 是的,结果才是最重要的。真正的麻烦是编写一个框架,该框架允许您生成的代码独立运行...在此花费时间。 |