programing

AngularJs 유닛 테스트 메모리 누수

telecom 2023. 10. 27. 21:43
반응형

AngularJs 유닛 테스트 메모리 누수

당신이 이미 알고 있듯이, 대량의 필기 단위 시험을 가지고 있는 우리들 중 많은 사람들이 사소한 문제를 해결할 수 없는 문제에 직면했습니다.저는 AngularJs 단위 테스트 가이드에 따라 재스민 구문으로 작성된 약 3500개 이상의 단위 테스트를 가지고 있습니다.카르마 러너를 사용하여 테스트를 실행합니다.

문제는 일부 메모리 누수로 인해 한 번에 실행할 수 없다는 것입니다.실행하는 동안 어떤 브라우저에서 실행되든 메모리가 쌓이고 어느 시점에서 브라우저가 충돌하고 연결이 끊어집니다.지금까지 제가 알고 있는 가장 좋은 해결책은 이 문제를 가진 커뮤니티에서 사용되는 테스트를 여러 번에 나눠서 한 번의 실행에서 나온 결과를 병합해서 정확한 범위를 얻는 것입니다.

이 문제를 처음 만났을 때 1000번 정도의 테스트를 받았습니다.실행할 수 있는 모든 브라우저를 사용해 본 후 테스트를 여러 번에 나누어 실행해 보았지만, 이것은 오랫동안 좋은 해결책이 아니라는 것이 밝혀졌습니다.이제 테스트는 완료 시간을 줄이기 위해 병렬로 실행되는 14개 이상의 단일 실행 방식으로 실행되지만, 여전히 IMO는 문제를 영구적으로 해결할 수는 없지만 리소스 제한(RAM, CPU)과 성가신 시간 소모로 인해 문제를 약간 지연시킵니다.

누군가는 브라우저에서 애플리케이션을 실행할 때와 같은 문제가 없는데도 내 코드에 메모리 누수가 있다고 주장할 수 있습니다.그것이 제가 이 문제를 부각시킬 예시적인 프로젝트를 만든 이유입니다.

이 문제를 재현하기 위해 저는 다음과 같이 메모리 소모량이 많은 Angular 서비스를 만들고 있습니다.

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; }
  };
});

그 후 이 서비스를 사용하여 많은 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());
    }
  };
});

그리고 마지막으로 나는 Angular unit testing guide에 제시된 대로 지시문에 대한 test definition과 함께 1000개의 test suit을 동적으로 등록하고 있습니다.

// 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

문제가 어디에 있는지 찾아서 최종적으로 해결할 수 있기를 기대하고 있습니다.

건배.

문제는 매번 시험이 끝난 후에 해야 하는 잊혀진 청소에 있었습니다.추가하면 메모리 소모량이 안정적이고 어느 브라우저에서나 테스트를 실행할 수 있기 때문에 테스트 횟수는 더 이상 중요하지 않습니다.

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 저장소에 더 나은 해결책을 찾거나 최소한 개발자들 사이에 이 정보를 더 빨리 퍼뜨리는 데 도움이 되는 문제를 만들었습니다.

이 답변이 이런 문제를 겪고 있는 많은 사람들에게 도움이 되길 바랍니다.다른 시험들은 리팩터를 다 하고 나서 정보도 작성하겠습니다.

건배!

언급URL : https://stackoverflow.com/questions/32998442/angularjs-unit-testing-memory-leaks

반응형