gpt4 book ai didi

AngularJs 单元测试内存泄漏

转载 作者:行者123 更新时间:2023-12-02 19:03:06 24 4
gpt4 key购买 nike

您可能已经知道,我们许多拥有大量书面单元测试的人都遇到过这个不易解决的问题。我在 Jasmine 中编写了大约 3500 多个单元测试。语法遵循 AngularJs unit testing指导。测试是通过 Karma 执行的运行者。

问题是由于某些内存泄漏,它们无法一次全部执行。运行它们时,无论它们在什么浏览器上运行,内存都会累积,并且在某些时候浏览器会崩溃并断开连接。据我所知,目前社区中遇到此问题的最佳解决方法是将测试拆分为多次运行,最后通过合并单次运行的结果来获得正确的覆盖范围。

当我第一次遇到这个问题时,我进行了大约 1000 次测试。在尝试使用所有可用的浏览器运行之后,我将测试分成多次运行,但事实证明,这在很长一段时间内都不是一个好的解决方法。现在,测试以 14 个以上的单次运行的形式执行,这些运行并行运行以减少完成时间,但在我看来,这仍然不能永久解决问题,但由于资源限制(RAM、CPU)和恼人的时间消耗而稍微延迟了问题。

有人可能会说我的代码中存在内存泄漏,尽管我在浏览器中运行应用程序时没有遇到任何问题,但我无法保证这一点。这就是为什么我创建了一个示例项目来突出这个问题。

为了重现这个问题,我正在创建一个 Angular 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());
}
};
});

最后,我使用 test definition 动态注册 1000 个测试套件。顺便说一句,对于按照 Angular unit testing 中建议编写的指令指南。

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

要尝试该示例,只需从 GitHub checkout 该项目即可在运行 karma start 之前运行:

$ 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 测试指令时的编译元素
  • 描述函数范围内的所有变量

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

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

干杯!

关于AngularJs 单元测试内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32998442/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com