2013-07-24 36 views
28

Sau nhiều lần đọc, có vẻ như cách được đề nghị để gọi một dịch vụ web từ một bộ điều khiển AngularJS là sử dụng một nhà máy và trả lời một lời hứa từ đó.

Ở đây tôi có một nhà máy đơn giản gọi API mẫu.

myApp.factory('MyFactory', ['$http',function($http) { 
var people = { 
     requestPeople: function(x) { 
      var url = 'js/test.json'; 
      return $http.get(url); 
     } 
    }; 
return people; 
}]); 

Và đây là cách tôi gọi nó trong bộ điều khiển

myApp.controller('MyCtrl1', ['$scope', 'MyFactory', function ($scope, MyFactory) { 
     MyFactory.requestPeople(22).then(function(result) { 
      $scope.peopleList = result; 
     }); 
}]); 

Trong khi nó hoạt động tốt, tôi muốn để có thể thử các result được thông qua trong khi then được gọi. Điều này có thể không?

Nỗ lực của tôi cho đến nay chưa tạo ra gì cả. Đây là nỗ lực của tôi:

//Fake service 
var mockService = { 
    requestPeople: function() { 
     return { 
      then: function() { 
       return {"one":"three"}; 
      } 
     } 

    } 
}; 


//Some setup 
beforeEach(module('myApp.controllers')); 
var ctrl, scope; 

beforeEach(inject(function ($rootScope, $controller) { 
    scope = $rootScope.$new(); 

    ctrl = $controller('MyCtrl1', { $scope: scope, MyFactory: mockService }); 
})); 

//Test 
it('Event Types Empty should default to false', inject(function() { 
    expect(scope.peopleList.one).toBe('three'); 
})); 

Các lỗi mà tôi nhận được khi chạy này ở Á hậu nghiệp, là

Lỗi Loại: 'undefined' không được một đối tượng (đánh giá 'scope.peopleList.one')

Làm cách nào để thử nghiệm này hoạt động với dữ liệu giả mạo của tôi?

+0

Tôi đã đọc về nó, nhưng bộ điều khiển của tôi không mất $ http. Bạn có thể giải thích về ý của bạn không? – Mendhak

Trả lời

38

Tôi không nghĩ $ httpBackend là những gì bạn đang ở đây, bạn muốn toàn bộ nhà máy được chế nhạo mà không có sự phụ thuộc vào $ http?

Hãy xem $q, đặc biệt là mẫu mã trong tiêu đề Kiểm tra. Vấn đề của bạn có thể được giải quyết với mã trông như thế này:

'use strict'; 

describe('mocking the factory response', function() { 

    beforeEach(module('myApp.controllers')); 

    var scope, fakeFactory, controller, q, deferred; 

    //Prepare the fake factory 
    beforeEach(function() { 
     fakeFactory = { 
      requestPeople: function() { 
       deferred = q.defer(); 
       // Place the fake return object here 
       deferred.resolve({ "one": "three" }); 
       return deferred.promise; 
      } 
     }; 
     spyOn(fakeFactory, 'requestPeople').andCallThrough(); 
    }); 

    //Inject fake factory into controller 
    beforeEach(inject(function ($rootScope, $controller, $q) { 
     scope = $rootScope.$new(); 
     q = $q; 
     controller = $controller('MyCtrl1', { $scope: scope, MyFactory: fakeFactory }); 
    })); 

    it('The peopleList object is not defined yet', function() { 
     // Before $apply is called the promise hasn't resolved 
     expect(scope.peopleList).not.toBeDefined(); 
    }); 

    it('Applying the scope causes it to be defined', function() { 
     // This propagates the changes to the models 
     // This happens itself when you're on a web page, but not in a unit test framework 
     scope.$apply(); 
     expect(scope.peopleList).toBeDefined(); 
    }); 

    it('Ensure that the method was invoked', function() { 
     scope.$apply(); 
     expect(fakeFactory.requestPeople).toHaveBeenCalled(); 
    }); 

    it('Check the value returned', function() { 
     scope.$apply(); 
     expect(scope.peopleList).toBe({ "one": "three" }); 
    }); 
}); 

Tôi đã thêm một số xét nghiệm xung quanh những gì $ áp dụng không, tôi không biết rằng cho đến khi tôi bắt đầu chơi với điều này!

Gog

+0

Điều này hoạt động hoàn hảo. Tôi đã đi đến một cái gì đó tương tự nhưng những gì tôi đã mất là 'trì hoãn' trả về một giá trị thích hợp, và bây giờ '$ scope.apply()' có ý nghĩa hơn. – Mendhak

+0

Tôi đã thử nghiệm các đơn vị cơ sở thành công trên mã này. Tuy nhiên, chuyển sang cú pháp "controller as", không rõ làm thế nào để sửa đổi kiểm tra để vượt qua. Vấn đề dường như là sử dụng ''MyCtrl1 như foo'' là vấn đề. Ngay cả các kiểm tra 'not.toBeDefined' không thành công với' TypeError: undefined không phải là một hàm'. –

+1

Ý nghĩa của tuyên bố 'spyOn' ở đây là gì. Tôi đã xóa nó khỏi các thông số thử nghiệm và kiểm tra vẫn được chuyển thành công. – Aakash

Các vấn đề liên quan