2016-09-16 3 views
0

Ich übe Winkel- und automatisierte Tests aus.Wie man Jasmine benutzt, um den Dienst der Angular App zu testen

Ich machte eine einfache App, um dem Benutzer die Stärke seines Passwortes zu sagen. Ursprünglich war alles innerhalb des PasswordControllers und $ scope wurde verwendet. Dann habe ich die Logik in einen Dienst umgesetzt. Die Steuerung und Service ist derzeit so:

myApp.controller("PasswordController", function ($scope, PasswordService) { 

    $scope.users = PasswordService.list(); 

    $scope.saveUser = function() { 
    PasswordService.save($scope.newUser); 
    $scope.newUser = {}; 
    } 

    $scope.delete = function (id) { 
    PasswordService.delete(id); 
    if($scope.newUser.id == id){ 
     $scope.newUser = {}; 
    } 
    } 

    $scope.edit = function(id) { 
    $scope.newUser = angular.copy(PasswordService.get(id)); 
    } 
}); 

myApp.service('PasswordService', function() { 

    //user with unique id 
    var uid = 1; 

    //user array 
    var users = [ 
    { 
     id: 0, 
     'name': 'a_test_name', 
     'password': 'a_test_pw', 
     'pwStrength': 'medium' 
    } 
    ]; 

    this.save = function(user) { 
    if (user.id == null) { 
     user.id = uid++; 
     this.grade(user); 
     users.push(user); 
    } 
    else { 
     for (i in users) { 
     if (users[i].id == user.id) { 
      users[i] = user; 
      this.grade(user); 
     } 
     } 
    } 
    } 

    this.get = function(id) { 
    for (i in users) { 
     if (users[i].id == id) { 
     return users[i]; 
     } 
    } 
    } 

    this.delete = function(id) { 
    for (i in users) { 
     if (users[i].id == id) { 
     users.splice(i, 1); 
     } 
    } 
    } 

    this.list = function() { 
    return users; 
    } 

    this.grade = function(user) { 
    var size = user.password.length; 
    if (size > 8) { 
     user.pwStrength = "strong"; 
    } 
    else if (size > 3) { 
     user.pwStrength = "medium"; 
    } 
    else { 
     user.pwStrength = "weak"; 
    } 
    } 
}); 

Meine Testfälle hatten alle gearbeitet worden, als alles, was in dem PasswordController war, aber ich kann nicht herausfinden, wie die Testfälle einzurichten, den Dienst zu nutzen. Dies ist der Test-Code ohne Änderungen: (so einige der Variablennamen nicht ganz aufreihen)

describe('PasswordController', function() { 
    beforeEach(module('myApp')); 

    var $controller; 
    var $scope; 
    var controller; 

    beforeEach(inject(function(_$controller_){ 
    // The injector unwraps the underscores (_) from around the parameter names when matching 
    $controller = _$controller_; 
    })); 

    describe("$scope.grade", function() { 

    beforeEach(function() { 
     $scope = {}; 
     controller = $controller("PasswordController", { $scope: $scope }); 
    }); 

    it("method should exist", function() { 
     expect($scope.grade).toBeDefined(); 
    }); 

    it('sets the strength to "strong" if the password length is >8 chars', function() { 
     $scope.password = 'longerthaneightchars'; 
     $scope.grade(); 
     expect($scope.strength).toEqual('strong'); 
    }); 

    it('strength to "medium" if the password length is >8 chars && <3 chars', function() { 
     $scope.password = 'between'; 
     $scope.grade(); 
     expect($scope.strength).toEqual('medium'); 
    }); 

    it('sets the strength to "weak" if the password length <3 chars', function() { 
     $scope.password = 'a'; 
     $scope.grade(); 
     expect($scope.strength).toEqual('weak'); 
    }); 
    }); 
}); 

ich nicht herausfinden kann, wie ich die Testfälle umwandeln würde den Passwordservice zu nutzen. Ich habe versucht, den PasswordService in den Controller zu injizieren und versuchte SpyOn zu verwenden, um den Dienst zu verspotten und es auf diese Weise zu verwenden, aber bis jetzt kein Glück.

beforeEach(module('myApp', function ($provide) { 
    PasswordService = jasmine.createSpyObj("PasswordService", ["save" ...]); 

controller = $controller("PasswordController", { $scope: $scope, PasswordSerice: PasswordService }); 

Alle Hinweise auf Links zu Tutorials sind willkommen. Vielen Dank.

Antwort

1

Da Sie den Controller und den Dienst trennen (was wahrscheinlich eine gute Sache war), macht es jetzt auch Sinn, die Tests zu trennen.

Sie sollten einen Test für den Controller erstellen. Der Test zielt nur auf die Methoden innerhalb des Controllers ab (speichern, löschen und bearbeiten).

Und dann erstellen Sie einen weiteren Test für den Dienst, der die Methoden innerhalb des Dienstes abdecken wird.

Ich werde ein Beispiel Beispiel für beide Szenarien erstellen Ihnen helfen:

describe('PasswordController Specification', function() { 
    beforeEach(module('myApp')); 

    var myPasswordController; 

    beforeEach(inject(function(_$controller_, $rootScope){ 
    myPasswordController= _$controller_('PasswordController', { 
     $scope: $rootScope.$new(); 
    }); 
    })); 

    it("Should save the user", inject(function(PasswordService) { 
    //setup 
    var myFakeUser = {id: 1, name: 'whatever'}; 
    myPasswordController.newUser = myFakeUser; 

    /* 
    Here I am spying the save method. This is necessary to check if it was 
    called. It will actually replace the original implementation with a 
    mocked empty function. And this is right because the controller 
    shouldn't if the service is doing what is supposed to. This is up for 
    the service test. 
    */ 
    spyOn(PasswordService, 'save'); 

    //action 
    myPasswordController.saveUser(myMockedUser); 

    //assertion 
    expect(PasswordService.save).toHaveBeenCalled(); 
    expect(myPasswordController.newUser).toBe({}); 
    })); 
}); 

und der Service-Test:

describe('PasswordService Specification', function() { 
    beforeEach(module('myApp')); 

    var myPasswordService; 

    beforeEach(inject(function(PasswordService){ 
    myPasswordService = PasswordService; 
    })); 

    it("Should save new user", inject(function() { 
    //setup 
    var numberOfUsers= myPasswordService.list().length; 
    var newUser = { 
     'name': 'a_test_name', 
     'password': 'a_test_pw', 
     'pwStrength': 'medium' 
    } 
    /* 
    Here I am spying the grade method. This is necessary to check if it was 
    called. It will actually replace the original implementation with a 
    mocked empty function. And this is right because we are only concerned 
    about the save method now. 
    */ 
    spyOn(myPasswordService, 'grade'); 

    //action 
    myPasswordService.save(newUser); 

    //assertion 
    expect(myPasswordService.grade).toHaveBeenCalled(); 
    expect(myPasswordService.list().length).toBe(numberOfUsers + 1); 
    })); 
}); 

Es gibt andere Dinge, die Sie testen können, aber ich hoffe, das gibt Sie einen Einblick, um Ihre Arbeit zu starten

+0

Vielen Dank SOOOO viel! Das war unglaublich hilfreich. – SuperCow

+0

In der Service-Test-Zeile: beforeEach (inject (Funktion (myPasswordService)) { myPasswordService = myPasswordService; })); sollten PasswordService in die Funktion übergeben werden, da dies der Name des Dienstes ist? Und dann setzen Sie myPasswordService = PasswordService (so weit wie Ihr Beispiel geht)? – SuperCow

+0

Es gibt keine richtige Antwort dafür. Du könntest das da haben, wenn du den PasswordService in vielen "it" -Blöcken verwendest. Es wäre nur eine Möglichkeit, Codezeilen zu reduzieren. Sie müssen nur analysieren, ob Ihr Code besser organisiert ist oder nicht. –

Verwandte Themen