2013-01-09 36 views
50

Tôi là dịch vụ thử nghiệm A, nhưng dịch vụ A phụ thuộc vào dịch vụ B (tức là dịch vụ B được đưa vào dịch vụ A).Tiêm dịch vụ phụ thuộc khi kiểm tra đơn vị Dịch vụ AngularJS

Tôi đã nhìn thấy this question nhưng trường hợp của tôi là một chút khác nhau bởi vì trong quan điểm của tôi nó có ý nghĩa hơn đối với giả dịch vụ B thay vì tiêm một ví dụ thực tế của dịch vụ B. Tôi muốn thử nó với một gián điệp hoa nhài.

Dưới đây là một thử nghiệm mẫu:

describe("Sample Test Suite", function() { 

    beforeEach(function() { 

    module('moduleThatContainsServiceA'); 

    inject([ 
     'serviceA', function(service) { 
     this.service = service; 
     } 
    ]); 

    }); 

    it('can create an instance of the service', function() { 
    expect(this.service).toBeDefined(); 
    }); 
}); 

Các lỗi tôi nhận được là:

Error: Unknown provider: serviceBProvider

Làm thế nào tôi có thể làm một cái gì đó như thế này?

+0

FWIW: Tôi đã hỏi một ** phiên bản QUnit ** của câu hỏi này [ở đây trên CodeReview.SE] (http://codereview.stackexchange.com/q/98519/10034). – Jeroen

Trả lời

43

Thực tế trong AngularJS Dependency Injection sử dụng quy tắc 'thắng trước'. Vì vậy, bạn có thể xác định dịch vụ của mình trong thử nghiệm ngay sau khi bao gồm mô-đun và phụ thuộc của bạn và sau đó khi dịch vụ A mà bạn đang thử nghiệm sẽ yêu cầu dịch vụ B sử dụng DI, AngularJS sẽ cung cấp phiên bản dịch vụ giả mạo B.

Điều này thường được thực hiện bằng cách định nghĩa mô-đun mới như MyAppMocks, đặt các dịch vụ/giá trị được mô phỏng ở đó và sau đó chỉ cần thêm mô-đun này làm phụ thuộc.

Loại (sơ đồ):

beforeEach(function() { 
    angular.module('MyAppMocks',[]).service('B', ...)); 
    angular.module('Test',['MyApp','MyAppMocks']); 
    ... 
+2

Bạn vừa mới cứu mạng tôi!: D Tôi đã tự sát mình đang cố gắng tiêm một dịch vụ giả lập vào một dịch vụ khác phụ thuộc vào nó, nhưng chỉ các xét nghiệm sẽ sử dụng phiên bản được chế nhạo, không phải là dịch vụ được tiêm. Bây giờ tôi có một mô-đun giả lập riêng biệt mà tôi tải sau khi mô-đun ứng dụng ghi đè các dịch vụ mong muốn. Làm việc như một say mê! –

+3

Thomas, bạn có thể chia sẻ một số chi tiết về giải pháp của mình không? Tôi có 2 mô-đun, mỗi mô-đun chứa một dịch vụ và dịch vụ_1 từ mô-đun đầu tiên được đưa vào dịch vụ_2 trong mô-đun thứ hai. Tôi đang tạo mô-đun giả lập với service_1 được cho là ghi đè lên dịch vụ gốc_1. Và nó được ghi đè, nhưng chỉ trong các bài kiểm tra, vì vậy khi tôi gọi service_2, nó vẫn đang sử dụng service_1 gốc bên trong. –

+3

Cách tôi xử lý [thêm mocks vào dịch vụ] (https://github.com/daniellmb/angular-test-patterns/blob/master/patterns/service.md#suggested-service-unit-test-setup-) – daniellmb

20

Giải pháp Valentyn làm việc cho tôi, nhưng có thay thế khác.

beforeEach(function() { 

    angular.mock.module("moduleThatContainsServiceA", function ($provide) { 
       $provide.value('B', ...); 
      }); 
}); 

Sau đó, khi dịch vụ AngularJS yêu cầu dịch vụ B bằng Dependency Injection, dịch vụ B của bạn sẽ được cung cấp thay cho Service B từ moduleThatContainsServiceA.

Bằng cách này bạn không cần phải tạo mô-đun góc bổ sung chỉ để giả lập Dịch vụ.

+0

Tuyệt vời. Trong trường hợp của tôi '...' được thay bằng '{}'. Bam, hoàn toàn loại bỏ một sự phụ thuộc. – 2mia

+0

Vấn đề với điều này là bạn vẫn thử dịch vụ của bạn bên trong thử nghiệm. Nói rằng bạn cần phải giả lập điều này ở một vài nơi và một cái gì đó thay đổi. Sau đó, bạn sẽ phải thay đổi từng tệp thay vì thay đổi ở một nơi. Vì lợi ích của bảo trì Valentyns câu trả lời nên được chấp nhận một (mà nó được). – perry

24

Tôi đã làm điều này trong CoffeeScript và tìm thấy một hình ảnh xác thực bổ sung. (Ngoài ra, tôi tìm thấy mã trên trang này được gây nhầm lẫn ngắn gọn.) Dưới đây là một ví dụ làm việc hoàn chỉnh:

describe 'serviceA', -> 
    mockServiceB = {} 

    beforeEach module 'myApp' # (or just 'myApp.services') 

    beforeEach -> 
     angular.mock.module ($provide) -> 
     $provide.value 'serviceB', mockServiceB 
     null 

    serviceA = null 
    beforeEach inject ($injector) -> 
     serviceA = $injector.get 'serviceA' 

    it 'should work', -> 
     expect(true).toBe(true) 
     #serviceA.doStuff() 

Nếu không dứt khoát trở về bằng null $provide.value, tôi giữ lấy Error: Argument 'fn' is not a function, got Object. Tôi đã tìm thấy câu trả lời trong số Google Groups thread này.

+1

Thử sử dụng trống 'return' thay vì' null'. Bằng cách này, javascript được tạo của bạn sẽ không có dòng 'return null' bổ sung ở cuối hàm. Thay vào đó, hàm 'beforeEach' của bạn sẽ không trả về gì cả. – demisx

+0

Tôi đang cố gắng sử dụng một mã tương tự tại thời điểm này, nhưng tôi nhận được một 'Cú pháp Cú pháp: Unexpecte' serviceA'' nếu tôi muốn sử dụng mã của bạn. Bất kỳ ý tưởng về cách giải quyết này? - Cũng sử dụng Coffeescript –

+0

@MathieuBrouwers, có lẽ bạn nên mở một câu hỏi mới. Tôi không chắc chắn những gì bạn đang đề cập đến chính xác, và tôi sẽ phải xem mã của bạn để trả lời. – jab

1

Đây là những gì phù hợp với tôi. Điều quan trọng là xác định một mô-đun thực để được chế giễu. Gọi angular.mock.module làm cho mô-đun thực có thể mô phỏng và cho phép mọi thứ được kết nối.

beforeEach(-> 
     @weather_service_url = '/weather_service_url' 
     @weather_provider_url = '/weather_provider_url' 
     @weather_provider_image = "test.jpeg" 
     @http_ret = 'http_works' 
     module = angular.module('mockModule',[]) 
     module.value('weather_service_url', @weather_service_url) 
     module.value('weather_provider_url', @weather_provider_url) 
     module.value('weather_provider_image', @weather_provider_image) 
     module.service('weather_bug_service', services.WeatherBugService) 

     angular.mock.module('mockModule') 

     inject(($httpBackend,weather_bug_service) => 
      @$httpBackend = $httpBackend 
      @$httpBackend.when('GET', @weather_service_url).respond(@http_ret) 
      @subject = weather_bug_service 
     ) 
    ) 
6

Tôi tìm phương pháp đơn giản nhất là chỉ tiêm dịch vụ B và giả lập. ví dụ. Dịch vụ xe phụ thuộc vào dịch vụ Engine. Bây giờ chúng ta cần phải động cơ giả khi kiểm tra xe:

describe('Testing a car', function() { 
     var testEngine; 

    beforeEach(module('plunker')); 
    beforeEach(inject(function(engine){ 
    testEngine = engine; 
    })); 

    it('should drive slow with a slow engine', inject(function(car) { 
    spyOn(testEngine, 'speed').andReturn('slow'); 
    expect(car.drive()).toEqual('Driving: slow'); 
    })); 
}); 

tham khảo: https://github.com/angular/angular.js/issues/1635

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