2013-01-09 9 views
50

私はサービスAをテストしていますが、サービスAはサービスBに依存しています(つまり、サービスBはサービスAに注入されています)。ユニットテスト時の依存サービスの注入AngularJSサービス

私がthis question見てきましたが、私の意見では、それはモックサービスBの代わりに、私はジャスミンのスパイでそれを嘲笑したいサービスBの実際のインスタンスを注入するより理にかなっているので、私の場合は少し異なっています。

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

私が手にエラーがある:

Error: Unknown provider: serviceBProvider

は、どのように私はこのような何かを行うことができ

は、ここでサンプルのテストですか?

+0

FWIW:[ここCodeReview.SE上]この質問の私は** QUnitのバージョンを求めてきました**(のhttp:/ /codereview.stackexchange.com/q/98519/10034)。 – Jeroen

答えて

43

実際、AngularJS Dependency Injectionは 'last wins'ルールを使用します。したがって、モジュールと依存関係を含めた直後にテストでサービスを定義することができます。テストしているサービスAがDIを使用してサービスBを要求すると、AngularJSはサービスBの模擬バージョンを提供します。

これはしばしばMyAppMocksのような新しいモジュールを定義し、そこに虚偽のサービスや値を入れてから、このモジュールを依存関係として追加するだけです。 (概略的に)の

種類:

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

あなたはちょうど私の命を救った!:D私は偽のサービスをそれに依存する別のサービスに注入しようとしていましたが、テストでは注入されたサービスではなく模擬バージョンを使用します。今私は、私が望むサービスを上書きするアプリケーションモジュールの後にロードするモックモジュールを別に持っています。魅力的な作品! –

+3

トーマス、あなたのソリューションに関する詳細を分かち合うことができますか?私は2つのモジュールを持っていて、それぞれにサービスがあり、第1のモジュールのservice_1が第2のモジュールのservice_2に注入されています。私は元のservice_1を上書きするはずのservice_1で模擬モジュールを作成しています。上書きされますが、テストでのみ使用されるため、service_2を呼び出すと、元のservice_1が使用されます。 –

+3

[サービスへのモック追加](https://github.com/daniellmb/angular-test-patterns/blob/master/patterns/service.md#suggested-service-unit-test-setup-) – daniellmb

20

Valentynソリューションは、私のために働いたが、別の選択肢があります。

AngularJSのサービス依存性の注入によって、要求サービスBは、サービスBのあなたのモックがmoduleThatContainsServiceAからではなくサービスBの提供されます次に
beforeEach(function() { 

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

このようにして、サービスをモックするために追加の角度モジュールを作成する必要はありません。

+0

優れています。私の場合、「...」は「{}」で置き換えられました。バムは、完全に依存関係を取り除いた。 – 2mia

+0

この問題は、依然としてテスト内でサービスを模擬していることです。いくつかの場所でこれを嘲笑して何か変わる必要があると言います。次に、1つの場所で変更する代わりに、各ファイルを変更する必要があります。保守性のために、バレンタインの回答は受け入れられたものでなければなりません(これはそれです)。 – perry

24

私はCoffeeScriptでこれをやっていて、余分なつかまえを見つけました。 (また、私は紛らわしい簡潔であることをこのページにコードを見つけました。)ここでは完全な作業例です:

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() 

明示的$provide.value後にnullを返さず、私はError: Argument 'fn' is not a function, got Objectを取得保管しました。私はこのGoogle Groups threadの答えを見つけました。

+1

'null'の代わりに空の' return'を使ってみてください。このようにして、生成されたjavascriptは関数の最後に 'return null'行を追加しません。代わりに、 'beforeEach'関数は何も返しません。 – demisx

+0

私はあなたのコードを使用すると、現時点で同様のコードを使用しようとしていますが、 'SyntaxError:Unexpecte string 'serviceA''を取得しました。どのようにこれを解決するための任意のアイデアですか? - Coffeescript –

+0

@MathieuBrouwersを使用している場合は、おそらく新しい質問を開く必要があります。私はあなたが何を正確に言及しているのか分からず、答えにあなたのコードを見なければならないでしょう。 – jab

1

これは私のために働いたものです。鍵は、嘲笑される実際のモジュールを定義することです。 angular.mock.moduleを呼び出すと、実際のモジュールが擬似的になり、物事を接続することができます。

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

最も簡単な方法は、サービスBを注入して模擬することです。例えばサービスカーはサービスエンジンに依存します。車をテストするときに今、私たちはモックEngineに必要があります。

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

参考:https://github.com/angular/angular.js/issues/1635

関連する問題