AngularJs单元测试内存泄漏

前端之家收集整理的这篇文章主要介绍了AngularJs单元测试内存泄漏前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
因为你可能已经知道我们许多拥有大量书面单元测试的人已经遇到了这个不是简单的可解决的问题。在AngularJs unit testing指南之后,我将以 Jasmine语法编写大约3500个单元测试。测试使用 Karma跑步机执行。

问题是由于一些内存泄漏,它们不能一次执行。在运行它们时,无论何时使用什么浏览器,在某些时候,浏览器崩溃并断开连接,内存将建立起来。现在我所了解的最好的解决方法是在社区中使用的,这个问题是在多次运行中分割测试,最后通过合并单次运行的结果来获得正确的覆盖。

当我第一次遇到这个问题,我有大约1000个测试。在尝试使用所有可用的浏览器进行运行后,我已经将测试分割成多个运行,但是事实证明,这不是很好的解决方案。现在测试在14个单独的运行中并行运行,以减少完成时间,而且仍然不能永久地解决问题,但是由于资源限制(RAM,cpu)和烦人的时间消耗而延迟测试。

有人可以认为我的代码中有内存泄漏,我无法保证,即使我在浏览器中运行应用程序时没有任何问题。这就是为什么我创建了一个突出显示这个问题的示例项目。

为了再现这个问题,我正在创建一个角度service,这是一个沉重的内存消耗如下所示:

app.factory('heavyLoad',function () {
  // init
  var heavyList = [];
  var heavyObject = {};
  var heavyString = '';

  // populate..

  return {
    getHeavyList: function () { return heavyList; },getHeavyObject: function () { return heavyObject; },getHeavyString: function () { return heavyString; }
  };
});

之后,我有一个简单的directive,它使用这个服务来初始化许多DOM元素:

app.directive('heavyLoad',function (heavyLoad) {
  return {
    scope: {},template: '' +
    '<div>' +
    ' <h1>{{title}}</h1>' +
    ' <div ng-repeat="item in items">' +
    '   <div ng-repeat="propData in item">' +
    '     <p>{{propData}}</p>' +
    '   </div>' +
    ' </div>' +
    '</div>',link: function (scope,element) {
      scope.items = heavyLoad.getHeavyList();
      scope.title = heavyLoad.getHeavyString();

      // add data to the element
      element.data(heavyLoad.getHeavyList());
    }
  };
});

最后,我正在动态地注册1000个测试套件,其中test definition是针对“0700指南”中建议的btw指令。

// define multiple suits with the same definition just for showcase
for (var i = 0; i < 1000; i += 1) {
  describe('heavyLoad directive #' + i,testDefinition);
}

要尝试这个例子,刚刚从GitHub结帐项目,然后运行业务开始运行:

$ npm install
$ bower install

我期待着找到问题所在,最终解决问题。

干杯

这个问题是在每次测试后需要做的被遗忘的清理。
添加后,测试次数不再重要,因为内存消耗是稳定的,测试可以在任何浏览器中运行。

添加了以前的测试定义here修改显示了成功执行3000个二进制登录测试的解决方案。

以下是测试的样子:

describe('testSuite',function () {
    var suite = {};

    beforeEach(module('app'));

    beforeEach(inject(function ($rootScope,$compile,heavyLoad) {
      suite.$rootScope = $rootScope;
      suite.$compile = $compile;
      suite.heavyLoad = heavyLoad;
      suite.$scope = $rootScope.$new();

      spyOn(suite.heavyLoad,'getHeavyString').and.callThrough();
      spyOn(suite.heavyLoad,'getHeavyObject').and.callThrough();
      spyOn(suite.heavyLoad,'getHeavyList').and.callThrough();
    }));

    // NOTE: cleanup
    afterEach(function () {
      // NOTE: prevents DOM elements leak
      suite.element.remove();
    });
    afterAll(function () {
      // NOTE: prevents memory leaks because of JavaScript closures created for 
      // jasmine Syntax (beforeEach,afterEach,beforeAll,afterAll,it..).
      suite = null;
    });

    suite.compileDirective = function (template) {
      suite.element = suite.$compile(template)(suite.$scope);
      suite.directiveScope = suite.element.isolateScope();
      suite.directiveController = suite.element.controller('heavyLoad');
    };

    it('should compile correctly',function () {
      // given
      var givenTemplate = '<div heavy-load></div>';

      // when
      suite.compileDirective(givenTemplate);

      // then
      expect(suite.directiveScope.title).toBeDefined();
      expect(suite.directiveScope.items).toBeDefined();
      expect(suite.heavyLoad.getHeavyString).toHaveBeenCalled();
      expect(suite.heavyLoad.getHeavyList).toHaveBeenCalled();
    });

});

有两件事需要清理:

>编译元素时使用$ compile进行测试指令
>描述函数范围内的所有变量

他们中的两个是棘手的,很难找出并考虑到。
对于我已经知道的第一个,但是直到我发现了与茉莉花在内部工作有关的第二个知识并没有多少帮助。
我已经在他们的GitHub存储库上创建了一个issue,它应该帮助找到更好的解决方案,或者至少在开发人员之间更快地传播这些信息。

我希望这个答案对许多有这个问题的人是有帮助的。在完成我所有其他测试之后,我也会写一些信息。

干杯!

猜你在找的Angularjs相关文章