2016-09-16 9 views
0

私はAngular and Automated Testingを実践しています。ジャスミンを使ってAngular Appのサービスをテストする方法

私は、パスワードの強さをユーザに伝える簡単なアプリを作った。当初はすべてがPasswordController内にあり、$ scopeを使用していました。それから、ロジックをサービスに移しました。コントローラおよびサービスは、現在、このされています。すべてがPasswordControllerにいたとき

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

私のテストケースは、すべての仕事をしていたが、私はサービスを利用するためのテストケースをセットアップする方法を見つけ出すことはできません。 (その変数名のいくつかは非常に並ばないでください)

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

私はPasswordServiceを使用するテストケースを変換したい方法を見つけ出すことはできません。これは変更せずにテストコードです。私はPasswordServiceをコントローラに注入しようとしましたが、spyOnを使ってサービスを模倣し、その方法で使用しましたが、これまでのところ運はありませんでした。

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

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

チュートリアルへのリンクのヒントは高く評価されます。どうもありがとう。

答えて

1

コントローラとサービスを分離するので(これはおそらく良いことでした)、今度はテストを分離することも理にかなっています。

コントローラのテストを1つ作成する必要があります。このテストでは、コントローラ内のメソッドのみを対象とします(保存、削除、編集)。

次に、サービス内のメソッドをカバーするサービスの別のテストを作成します。

両方のシナリオはあなたを助けるためにのために私は例の例を作成します。

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

とサービスのテスト:

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

ありますが、テストすることができ、他のものがあるが、私はこれが与える希望をあなたの仕事を始める洞察

+0

ありがとうSOOOO!それは信じられないほど役に立つものでした。 – SuperCow

+0

サービステスト行で: beforeEach(inject(function(myPasswordService){ myPasswordService = myPasswordService; })); これはサービスの名前なので、PasswordServiceを関数に渡す必要がありますか?そして、myPasswordService = PasswordServiceを設定してください(あなたの例がある限り)? – SuperCow

+0

正解はありません。多くの「it」ブロックでPasswordServiceを使用する場合、そこにそれを置くことができます。これはコード行を減らす単なる方法です。あなたのコードがより組織化されているかどうかを分析するだけです。 –

関連する問題