wake-up-neo.com

Testen der modulare Instanz von Angular UI Bootstrap

Dies ist eine etwas weitergehende Frage an diese: Spottendes $ -Modal in AngularJS-Unit-Tests

Die referenzierte SO ist eine ausgezeichnete Frage mit sehr nützlicher Antwort. Die Frage, die mir danach bleibt, ist folgende: Wie teste ich den modalen Instanzcontroller? In der referenzierten SO wird der aufrufende Controller getestet, aber der modale Instanzcontroller wird überlagert. Letzteres sollte wohl auch getestet werden, aber das hat sich als sehr schwierig erwiesen. Hier ist der Grund:

Ich werde dasselbe Beispiel aus dem referenzierten SO hier kopieren:

.controller('ModalInstanceCtrl', function($scope, $modalInstance, items){
  $scope.items = items;
  $scope.selected = {
    item: $scope.items[0]
  };

  $scope.ok = function () {
    $modalInstance.close($scope.selected.item);
  };

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
});

Mein erster Gedanke war also, dass ich die Steuerung direkt in einem Test instanziieren würde, genau wie jede andere getestete Steuerung:

beforeEach(inject(function($rootScope) {
  scope = $rootScope.$new();
  ctrl = $controller('ModalInstanceCtrl', {$scope: scope});
});

Dies funktioniert nicht, weil in diesem Zusammenhang ein Anbieter nicht über $ modalInstance verfügt, da Angular von der UI-Modal bereitgestellt wird.

Als nächstes wende ich mich an B: Verwenden Sie $ modal.open, um den Controller zu instanziieren. Dies wird wie erwartet laufen:

beforeEach(inject(function($rootScope, $modal) {
  scope = $rootScope.$new();
  modalInstance = $modal.open({
    template: '<html></html>',
    controller: 'ModalInstanceCtrl',
    scope: scope
  });
});

(Beachten Sie, dass die Vorlage keine leere Zeichenfolge sein kann oder die Verschlüsselung fehlschlägt.)

Das Problem ist jetzt, dass ich keine Einsicht in den Geltungsbereich habe. Dies ist der übliche Weg für die Erfassung von Komponententests, usw. In meinem echten Code ruft der Controller einen Ressourcendienst auf, um eine Auswahlliste aufzufüllen. Bei meinem Versuch, dies zu testen, wird erwartet, dass erwartet wird, dass der Dienst, den mein Controller verwendet, erfüllt wird, und ich möchte überprüfen, ob der Controller das Ergebnis in seinen Geltungsbereich stellt. Das Modal erstellt jedoch einen new - Bereich für den modalen Instanzcontroller (wobei ich den Bereich benutze, den ich als Prototyp übergeben habe), und ich kann nicht herausfinden, wie ich ein Loch dieses Bereichs erhalten kann. Das modalInstance-Objekt hat kein Fenster in die Steuerung.

Irgendwelche Vorschläge, wie man das testen kann?

(Anmerkung: Das Verhalten beim Erstellen eines abgeleiteten Bereichs für den modalen Instanzcontroller ist nicht unerwartet - es ist dokumentiertes Verhalten. Meine Frage, wie er getestet werden kann, ist trotzdem gültig.)

25
David Pisoni

Ich teste die Controller, die in modalen Dialogen verwendet werden, indem ich den Controller direkt instanziiere (genauso wie Sie es anfangs gedacht haben).

Da es keine gespielte Version von $modalInstance gibt, erstelle ich einfach ein Mock-Objekt und gebe es in den Controller.

var modalInstance = { close: function() {}, dismiss: function() {} };
var items = []; // whatever...

beforeEach(inject(function($rootScope) {
  scope = $rootScope.$new();
  ctrl = $controller('ModalInstanceCtrl', {
      $scope: scope, 
      $modalInstance: modalInstance, 
      items: items
  });
}));

Nun sind die Abhängigkeiten für den Controller erfüllt und Sie können diesen Controller wie jeden anderen Controller testen.

Zum Beispiel kann ich spyOn(modalInstance, 'close') ausführen und dann behaupten, dass mein Controller den Dialog zur richtigen Zeit schließt.

30
Sunil D.

Wenn Sie Jasmin verwenden, können Sie alternativ den $uibModalInstance mit der createSpy-Methode simulieren:

beforeEach(inject(function ($controller, $rootScope) {
  $scope = $rootScope.$new();
  $uibModalInstance = jasmine.createSpyObj('$uibModalInstance', ['close', 'dismiss']);

  ModalCtrl = $controller('ModalCtrl', {
    $scope: $scope,
    $uibModalInstance: $uibModalInstance,
  });
}));

Und testen Sie es, ohne spyOn für jede Methode aufrufen zu müssen. Angenommen, Sie haben zwei Methoden für den Umfang: cancel() und confirm():

it('should let the user dismiss the modal', function () {
  expect($scope.cancel).toBeDefined();
  $scope.cancel();
  expect($uibModalInstance.dismiss).toHaveBeenCalled();
});

it('should let the user confirm the modal', function () {
  expect($scope.confirm).toBeDefined();
  $scope.confirm();
  expect($uibModalInstance.close).toHaveBeenCalled();
});
13
yvesmancera

Das gleiche Problem tritt mit $ uidModalInstance auf und Sie können es auf ähnliche Weise lösen:

var uidModalInstance = { close: function() {}, dismiss: function() {} };

$ctrl = $controller('ModalInstanceCtrl', {
   $scope: $scope,
   $uibModalInstance: uidModalInstance
});

oder als @yvesmancera können Sie stattdessen die Methode jasmine.createSpy verwenden:

var uidModalInstance = jasmine.createSpyObj('$uibModalInstance', ['close', 'dismiss']);

$ctrl = $controller('ModalInstanceCtrl', {
   $scope: $scope,
   $uibModalInstance: uidModalInstance
});
0
kris_IV

Befolgen Sie die angegebenen Schritte:

  • Definieren Sie den Stub für ModalInstance wie unten angegeben

            uibModalInstanceStub = {
                close: sinon.stub(),
                dismiss: sinon.stub()
            };
    
  • Übergeben Sie den modalen Instanz-Stub, während Sie den Controller erstellen

        function createController() {
            return $controller(
                ppcConfirmGapModalComponentFullName,
                {
                    $scope: scopeStub,
                    $uibModalInstance: uibModalInstanceStub
                });
        }
    });
    
  • Die Stub-Methoden close (), dismiss () werden als Teil der Tests aufgerufen

    it ('Confirm Modal - Verify Confirm Action, bei ok () - Aufrufen ruft die Funktion modalInstance close () auf'), function () { action = 'Ok'; scopeStub.item = testItem; createController ( ); scopeStub.ok (); });

0
Dilip Nannaware