简体   繁体   中英

How to: mock module dependencies

Tearing my hair out on this one.

I have the following module/controller I wish to test

angular
    .module('monitor.tableLord.controller', ['monitor.wunderTable'])
    .controller('TableLordController', TableLordController);

    TableLordController.$inject = ['$scope', 'historyState'];
    function TableLordController($scope, historyState) {
        ....some code....
    }

The module monitor.wunderTable contains a directive that should be loaded before the controller, but the controller I want to test does not actually depend on monitor.wunderTable. monitor.wunderTable does however have a LOT of other dependencies....

My testfile:

describe('TableLordController', function() {
    var $scope, historyState;

    beforeEach(function() {
        angular.module('monitor.wunderTable', []);
        module('monitor.tableLord.controller');
    });

    beforeEach(angular.mock.inject(function($rootScope, $controller) {
            $scope = $rootScope.$new();
            $controller('TableLordController', {$scope: $scope, historyState: {}});
    }));

    it('loads', function() {
        $scope.$digest();
    });
});

For some reason (I didn't think this should be possible), my mock version of monitor.wunderTable is interfering with the tests i have for this module. Every test of the controller defined in this module now fails with: "Argument 'WunderTableController' is not a function, got undefined".

I case it is relevant, here is my the definition of monitor.wunderTable:

angular
    .module('monitor.wunderTable', [
        'ui.grid',
        'ui.grid.infiniteScroll',
        'ui.grid.autoResize',
        'monitor.wunderTable.service'
     ])
    .controller('WunderTableController', WunderTableController)
    .directive('wunderTable', wunderTable);

function wunderTable(){...}
WunderTableController.$inject = [];
function WunderTableController(...){...}

Edit: Posts suggesting that I remove the module dependency (as it is not strictly needed) will not be accepted as correct answer (and possibly downwoted).

Your confusion comes from misunderstanding how modules work in Angular. Modules are stored inside angular . Once they are overriden, they are overriden for the current test run, not for the current spec. Module mocking isn't supported by ngMock (it would require some substantial changes in Angular core) and beforeEach won't help anything.

Unless you want to run test suites in separate runs, the solution is to backup the module before mocking it. In some cases angular.extend and angular.copy are unable to handle complex objects properly. Object.assign , jQuery.extend or node-extend may be better candidates. In the case of extend s deep copy can also used if necessary.

So in one test suite it is

var moduleBackup = angular.module('monitor.wunderTable');
angular.module('monitor.wunderTable', []);

describe('TableLordController', function() {
    ...

And in another

Object.assign(angular.module('monitor.wunderTable'), moduleBackup);

describe('WunderTableController', function() {
    ...

The good thing about TDD is that it clearly indicates the flaws in app design and teaches the developer to write test-friendly code in immediate and ruthless manner. Module dependency implies that the components inside the module depend on the components from another one. If they doesn't or they are coupled too tightly, this can be considered a potential flaw and the subject for refactoring.

The fact that the solution is hack-ish and tends to break makes it unfit for testing.

TL;DR: Yes, you have to remove the module dependency.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM