单元测试-如何测试JavaScript缩小输出

unit testing - How to test JavaScript minification output

本文关键字:JavaScript 缩小 输出 测试 何测试 单元测试      更新时间:2023-09-26

我们最近升级到了JavaScript缩小库的新版本。

在测试团队进行了大量的质量保证工作后,我们发现新版本的minifier存在一个问题,该问题改变了代码块背后的意图和含义。

(人生教训:除非你真的确信你需要新版本,否则不要升级JS迷你程序。)

minifier用于客户端JavaScript代码,主要强调与DOM相关的活动,而不是太多的"业务逻辑"。

迷你机升级所破坏的简化示例:

function process(count)
{
     var value = ""; 
     value += count; //1. Two consecutive += statements
     value += count;
     count++;        //2. Some other statement
     return value;   //3. Return
}

被错误地缩小为以下内容:

function process(n){var t="";return t+n+n,n++,t}

虽然我们可以编写一些单元测试来捕捉一些潜在的问题,但考虑到JavaScript非常依赖DOM交互(数据输入等),如果没有用户测试(非自动化),很难进行彻底的测试。我们曾考虑过使用像Esprima这样的JS到AST库,但考虑到可以对缩小后的代码进行更改的性质,它会产生太多的误报。

我们还考虑过编写具有代表性的测试,但这似乎是一项永无止境的任务(很可能会错过案例)。

仅供参考:这是一个非常复杂的web应用程序,有几十万行JavaScript代码。

我们正在寻找一种测试缩小过程的方法,而不是"再次、彻底、重复地测试所有东西"。我们希望在这个过程中应用更严格/更科学的方法。

理想情况下,如果我们有更好的科学测试方法,我们可以尝试多个迷你程序,而不用担心每个迷你程序都会以新的微妙方式破坏我们的代码。

更新:

我们的一个想法是:

  1. 使用旧版本缩小
  2. 美化它
  3. 新版本的minimy
  4. 美化,以及
  5. 视觉差异

这看起来确实是个好主意,但差异是如此普遍,以至于diff工具几乎将每一行都标记为不同。

您是否考虑过单元测试框架,如QUnitjs?编写单元测试将是一项相当艰巨的工作,但最终您将拥有一个可重复的测试过程。

我觉得您需要开始在CI(连续集成环境)中使用自动化单元测试。QUnit已经被抛弃了,但实际上QUnit是一个相当弱的测试系统,它的断言至少是赤裸裸的(它甚至没有真正使用好的基于断言的语法)。它只是稍微符合TDD的条件,并且也不能很好地处理BDD。

就我个人而言,我建议Jasmine使用JsTestDriver(它可以使用其他UT框架,也可以使用自己的框架,速度非常快……尽管它有一些稳定性问题,我真的希望他们能解决),并设置单元测试,通过多次比较来检查缩小过程。

一些比较可能需要:

  • 原始代码&其功能如预期
  • 与缩小的代码相比(这是BDD的用武之地,在缩小的代码中期望相同的功能性能/结果)
  • 我甚至会更进一步(取决于你的缩小方法),进行一个测试,然后美化缩小并进行另一次比较(这会使你的测试更稳健,更确保有效性)

这些类型的测试就是为什么你可能会受益于像Jasmine这样的支持BDD的框架,而不仅仅是纯粹的TDD(比如你发现的视觉差异的结果是一团糟),因为你正在测试行为和比较以及功能/行为的前/后状态,而不只是如果a是真的,并且在解析后仍然是真的。

设置这些单元测试可能需要一段时间,但这是一种迭代方法,需要大量的代码库。。。尽早快速测试你最初的关键瓶颈或脆弱点,然后将测试扩展到所有内容(我一直以来组建团队的方式是,从现在开始的任何东西都不被认为是完整的,除非它有单元测试……任何没有单元测试并且必须更新/接触/维护的旧东西都必须在接触时编写单元测试,这样你就可以以更易于管理和逻辑的方式不断改进和减少未测试代码的数量,同时增加你的代码覆盖)。

一旦你在CI中启动并运行了单元测试,你就可以将它们绑定到你的构建过程中:没有单元测试的失败构建,或者当单元测试失败时发出警报,主动监控每次签入等。使用JSDoc3等自动生成文档。

您所描述的问题是CI和单元测试是为什么而构建的,更具体地说,在您的案例中,这种方法最大限度地减少了代码库大小的影响。。。尺寸并没有使它变得更复杂,只是使全面测试的持续时间更长。

然后,将其与JSDoc3相结合,您的造型比90%的大多数前端商店都要好。在这一点上,它非常强大,对工程师来说非常有用,而且它会自我延续。

我真的可以继续谈论这个话题,你如何处理它,让团队团结起来支持它,使它自我形成和自我延续,有很多细微之处,最重要的是编写可测试的代码。。。但从概念层面来说编写单元测试并将其自动化。总是

长期以来,前端开发人员一直在半推半就地开发,没有应用实际的工程严谨性和纪律性。随着前端变得越来越强大和炙手可热,这种情况必须改变,而且正在改变。前端/RIA应用程序的良好测试、良好覆盖、自动化测试和持续集成的概念是这一变化的巨大需求之一。

您可以看看类似Selenium Web Driver的东西,它允许您在各种环境中自动测试Web应用程序。有一些云托管的VM解决方案可用于进行多环境测试,因此当它在Webkit中工作而在IE中不工作时,您不会被发现。

您绝对应该考虑使用源映射来帮助调试最小化的JavaScript。源映射还可以使用JavaScript的超集,如CoffeeScript或我最喜欢的TypeScript。

我使用闭包编译器,它不仅缩小,而且会创建源映射。更不用说它是最具攻击性和产生最小文件的。最后,你必须知道缩小中发生了什么,并编写兼容的代码,你的示例代码可以使用一些重构。

查看源代码地图上的这篇文章:http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/

还可以查看闭包编译器的文档,它有关于如何编写更好的缩小代码的建议:https://developers.google.com/closure/compiler/

不是一个测试解决方案,但切换到TypeScript来编写像您这样的大型JS应用程序怎么样?

我用TypeScript和它默认的min引擎测试了它,它运行得很好。

假设您的count参数是一个数字。

类型脚本为:

class ProcessorX {
    ProcessX(count: number): string {
        var value = '';
        value += count.toString();
        value += count.toString();
        count++;
        return value;
    }
}

它产生的js是这样的:

var ProcessorX = (function () {
    function ProcessorX() { }
    ProcessorX.prototype.ProcessX = function (count) {
        var value = '';
        value += count.toString();
        value += count.toString();
        count++;
        return value;
    };
    return ProcessorX;
})();

然后缩小为:

var ProcessorX=function(){function n(){}return n.prototype.ProcessX=function(n){var t="";return t+=n.toString(),t+=n.toString(),n++,t},n}()

它在jsfiddle上。

如果你的countstring,那么这个小提琴。

我们在高级模式下使用闭包编译器,它可以缩小和更改代码,因此我们也编译单元测试,因此您可以考虑将测试与代码一起缩小并这样运行。