2016-11-24 4 views
0

Dies ist mein Controller.

(function() { 
    'use strict'; 

    app.controller('NavController', navController); 

    function navController($rootScope, $scope, $location, $window, NavFactory) { 

     $scope.menuConfig = null; 
     $scope.menuItems = []; 
     $scope.isActive = isActive; 
     $scope.toggleBurgerMenu = toggleBurgerMenu; 
     $scope.toggleDeviceSettings = toggleDeviceSettings; 

     $rootScope.$watch('dictionary', function(dictionary) { 
      if (dictionary) { 
       init(); 
      } 
     }); 

     function init() { 
      $scope.menuConfig = $rootScope.config.navigation; 
      NavFactory.GetMenuItems().then(onGetMenuItems, $scope.onAPIError); 
     } 

     function onGetMenuItems(response) { 
      $scope.moduleConfig = response.moduleConfig; 
      $scope.menuItems = response.menuItems; 
     } 
    } 
})(); 

Dies ist mein Test-Suite (karma, Jasmin) beschreiben ('NavController Funktion', function() {

var $rootScope, $scope, $location, $window, $controller, createController, NavFactory, CacheFactory, toastr; 

beforeEach(module('mockedDashboard')); 

beforeEach(inject(function(_$rootScope_, _$controller_, _$location_, _$window_, _NavFactory_, _toastr_) { 
    $location = _$location_; 
    $window = _$window_; 
    toastr = _toastr_; 

    $rootScope = _$rootScope_; 
    $rootScope.dictionary = jsDictionary; 
    $rootScope.config = jsConfig; 
    $rootScope.config.contentFolder = '_default'; 

    $scope = _$rootScope_.$new(); 
    $scope.burgerMenuActive = false; 
    //mock the parent controller function 
    $scope.navigate = function(path) { 
     $location.path('/' + path); 
    }; 
    // end mock 

    createController = function() { 
     return _$controller_('NavController', { 
      '$scope': $scope 
     }); 
    }; 
    $controller = createController(); 
})); 

// We are using CacheFactory in this project, when running multiple tests on the controller 
// we need to destroy the cache for each test as the controller is initialized for each test. 
afterEach(inject(function(_CacheFactory_) { 
    CacheFactory = _CacheFactory_; 
    CacheFactory.destroy('defaultCache'); 
})); 

describe('init()', function() { 

    it('should call NavFactory.GetMenuItems and set moduleConfig and menuItems on $scope', inject(function(_$httpBackend_) { 

     var $httpBackend = _$httpBackend_; 

     expect($scope.moduleConfig).toBe(undefined); 
     expect($scope.menuItems.length).toBe(0); 

     var responseData = [{ 
      "path": "stats", 
      "url": "./app/modules/dashboard/modules/score/score.index.html", 
      "icon": "fa fa-fw fa-pie-chart", 
      "dashboardEnabled": true, 
      "burgerMenu": true, 
      "barMenu": false, 
      "barMenuOrder": -1, 
      "bottomMenu": true, 
      "bottomMenuOrder": 3, 
      "order_sm": 1, 
      "order_md": 2, 
      "order_lg": 2 
     }]; 

     $httpBackend.expectGET('../content/_default/config/modules.json').respond(responseData); 
     $httpBackend.flush(); 

     expect($scope.moduleConfig).not.toBe(undefined); 
     expect($scope.menuItems.length > 0).toBe(true); 
    })); 
});}); 

Ich erwartete ein $ Umfang in sich zu tragen. $ Digest (), um den Beobachter zu feuern, um init() zu laufen, aber es läuft gut, wie es ist und die Tests bestehen.

Das ist kein Problem, ich versuche nur zu verstehen, warum es läuft, weil ich verstehe nicht, wie der Beobachter feuert, was bewirkt, dass er läuft

+1

Woher kommt das 'jsDictionary' in' $ rootScope.dictionary = jsDictionary; 'kommen? – Jagrut

+0

Normalerweise würde es aus einer JSON-Datei im Bootstrap kommen, aber zu Testzwecken ist es ein globales Javascript-Objekt, das mit den Testdateien geladen wird. Es ist schmutzig, aber es funktioniert, während ich lerne, andere Fehler zu lösen, die ich/wir beim Aufbau unserer App gemacht haben. Alle diese Unit-Tests werden nach dem Build durchgeführt. Wir lernen so viel und in Zukunft werden wir einen TDD-Ansatz verfolgen. – Stuart

Antwort

2

Meiner Meinung nach ist es eine schlechte Idee, den Controller im globalen Umfang zu initialisieren. Dies liegt daran, dass Sie zukünftig, wenn Sie einige andere Controller, die logisch unabhängig sind, testen möchten, immer noch jeden Controller für jeden it() Block initialisieren, für den ich keinen Grund sehe, dies zu tun.

Was, warum Ihre $watch gefeuert wird, Sie jsDictionary auf eine $rootScope setzen und es für jeden it() Block initialisiert. In Ihrem Controller-Code, für die $watch Sie nur überprüfen, ob der Wert existiert, die es wird, wie Sie es in den vorherigen Zeilen festlegen und daher ruft es den init() Block. Der richtige Weg, um die $ Uhr der Verwendung wäre:

$rootScope.$watch('dictionary', function(oldVal, newVal){ 
}); 

Eine bessere Art und Weise zu tun, wäre ein describe() Block für jeden Controller zu erstellen, setzen Sie Ihre beforeEach() Sachen in der describe() und auch Ihre it() Block, diejenigen, die im Zusammenhang mit diesem bestimmten Controller. Dies würde Ihnen auch helfen, modulare Testfälle zu erstellen.

+0

Ich habe Uhren so aufgebaut gesehen, und das tue ich auch. Die Wörterbuchüberwachung ist so eingestellt, dass sie prüft, ob sie existiert, weil wir Rassenprobleme mit ihrer Verwendung haben, bevor sie gesetzt wird. Also warten wir auf sie so ... JETZT ist dies jedoch gelöst worden, aber die Codebasis, von der ich arbeiten muss, ist auf einem anderen Zweig des Codes, wo dieses Problem noch existiert, daher überprüfe ich auf seine Existenz. Ich dachte nicht, dass die Beobachter laufen würden, bis ein '$ digest()' aufgerufen wurde? Wird '$ digest()' irgendwo automatisch aufgerufen? – Stuart

+0

Könnten Sie bitte erläutern, was Sie meinen, wenn Sie den Controller im globalen Geltungsbereich initialisieren? Dieser Controller ist in IIFE verpackt und nicht auf $ rootScope? – Stuart

+1

Angular hat viele eingebaute Funktionen, die '$ digest()' automatisch auslösen. Asynchrone Aufrufe sind einer von ihnen. In Ihrem Code löst '$ httpBackend.flush()' den Digest-Zyklus aus. – Jagrut