AngularJs unit testing memory leaks

前端 未结 1 1326
挽巷
挽巷 2020-12-12 20:34

as you may already know many of us who have a large quantity of written unit test has met with this not trivially solvable problem. I have around 3500+ unit tests written in

相关标签:
1条回答
  • 2020-12-12 20:59

    The problem was in the forgotten clean-up that needs to be done after each test. After adding it the number of tests does not matter anymore because the memory consumption is stable and the tests can be run in any browser.

    I have added a modification of the previous test definition here that shows the solution with successfully executing 3000 dinamically registered tests.

    Here is how the test looks like now:

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

    There are two things that need to be cleaned-up:

    • compiled element when using $compile for testing directives
    • all variables in the describe functions scope

    The two of them are tricky and hard to find out and take into consideration. For the first one I already knew but it didn't helped much until I've discovered the second which is related with how Jasmine works inside. I have created an issue on their GitHub repository which should help finding better solution or at least spread this information among developers faster.

    I hope that this answer will be helpful for lot of people having this problem. I will write some info too after I finish refactoring all my other tests.

    Cheers!

    0 讨论(0)
提交回复
热议问题