1

使命:

我有一个遗留的、未缩小的 Angular 1 应用程序,其中包含数千个测试,都通过了。我在代码中引入了缩小和修改。如果我将库和应用程序代码分开,测试将继续工作。但是,我无法破坏应用程序代码,因为这样做会将合同破坏回 libs 文件。

我希望能够破坏应用程序代码并保持单元测试正常工作。

当前状态:

我已经创建了两条路径来规避这个问题,但我并不满意,因为单元测试并没有真正触及将要投入生产的代码......他们正在触及为避免重整问题而创建的中间立场。

路径 1

一条路径输出 alibs.min.js和 an app.min.js。里面libs.min.js有 Angular、Underscore 等 - 使用它们提供的缩小版本。本质libs.min.js上只是一堆已经缩小的文件连接在一起。 app.min.js包含我们的应用程序代码,已缩小但未损坏。

路径 2

第二个路径创建一个combined.min.js文件。这就是生产。在这个文件中,依次是 Angular、Underscore 等,然后是我们的应用程序代码。所有这些都未缩小(包括库)连接到这个文件中,然后一起被修改/缩小,以便我们得到一个可以引用我们的应用程序代码和库代码的单一源映射。这在浏览器中有效,但单元测试中断,因为combined.min.js不包含所需的仅测试库angular-mocks

问题:

由于 Karma 加载了这些文件,因此针对路径一进行测试是可行的。这很好,但它不是将要投入生产的实际代码,所以我不认为这是一场胜利。

  1. libs.min.js
  2. angular-mocks(未缩小 - 并且可以绑定到 Angular,因为我们使用的是提供的缩小版本)
  3. app.min.js(缩小但未损坏,因为损坏将合同破坏回 libs.min.js)
  4. *.spec.js

测试路径 2 不起作用,因为我们按以下顺序加载内容:

  1. 组合.min.js
  2. 角度模拟(未缩小)
  3. *.spec.js

卡布姆。我们的应用程序代码已经连接了它的绑定,所以 angular-mocks 为时已晚。除了将库和应用程序加载到单独的文件中(例如在路径一中)之外,我看不到任何解决此问题的方法。

一些测试通过了,但那些试图引用我们依赖 angular-mocks 的任何东西的测试都失败了。

我知道我可以提供一个输入源映射,app.min.js以便我可以单独缩小/修改应用程序代码(但始终反对libs.min.js),但我不确定这是最好的路线。我想把东西保存在一个大文件中,但如果没有其他办法,看起来我用来破坏/缩小(UglifyJS)的库支持输入源映射......

哦。此外,我们没有使用 Grunt 或 Gulp。只需直接 NPM 即可完成所有这些工作。但是如果有一个 grunt 或 gulp 库能以某种方式解决这个问题,我可以对其进行 NPM 化。

4

1 回答 1

0

我想通了。最初的问题在诊断出了什么问题时并不完全正确。我怀疑其他人会偶然发现这种类型的问题,但我会把它留在这里以防万一。

问题1:

通过将库和应用程序一起缩小,我们要求一些库在严格模式下工作,而这些库原本不是严格模式下的。要么它们不在自执行函数中,要么从其他库泄漏了全局“use strict”……这可能发生的原因有很多。

就我而言,罪犯是 Restangular。1.4 版不能在严格模式下工作,因为“数据”有一个隐含的定义。我确信这是旧版本的疏忽,但它会在 Phantom 中导致“没有这样的属性‘数据’”的错误。

这是一件容易解决的事情。最有可能的是,只需升级到较新的版本。此应用程序不允许升级到较新版本,所以现在我只是手动添加了“var data”来欺骗定义。

问题2:

我们的 Jasmine 测试开始失败。他们正在执行和使用缩小的代码。针对缩小代码运行时发生的情况的示例:

var result,
    someObject = {foo: "bar"};

httpBackend.whenGET("/something").respond(someObject);

somethingService.then(function(response) {
   result = response;
});

httpBackend.flush();

expect(result).toBe(someObject);  // fail.  {foo: "bar"} is not {route: "something", getRestangularUrl: function...}

通常这是可行的,因为 ngMocks 绕过了 Restangular 的响应包装器;您响应的对象将传递给已解决的承诺,而无需添加 Restangular 元数据。所以{foo: "bar"}仍然完全正确{foo: "bar"}

但是,由于我们在应用代码之后加载了 ngMocks(参见问题中的“路径 2”),因此不再绕过 Restangular 的响应。因此,Restangular 使用所有额外的元数据扩展了您的预期响应。

因此,我们{foo: "bar"}变成了一个完整的 Restangular 响应,其中包含 {foo: "bar"},但不仅仅是 {foo: "bar"}

解决方案:不要测试整个对象。检查特定键和该特定键的值。

var result;

httpBackend.whenGET("/something").respond({foo: "bar"});

somethingService.then(function(response) {
   result = response;
});

httpBackend.flush();

expect(result.foo).toEqual("bar");  // pass

我认为以这种方式进行测试会更好,因为它可以更准确地表示一旦 ngMocks 消失后实际会发生什么。

于 2017-01-17T20:32:14.930 回答