ホームページ >ウェブフロントエンド >jsチュートリアル >AngularJSの単体テスト:サービス、コントローラー、プロバイダー

AngularJSの単体テスト:サービス、コントローラー、プロバイダー

Lisa Kudrow
Lisa Kudrowオリジナル
2025-02-20 08:31:09864ブラウズ

AngularJSの単体テスト:サービス、コントローラー、プロバイダー

キーテイクアウト

  • AngularJSは、依存関係噴射を使用してユニットテストを容易にし、サービス、コントローラー、プロバイダーなどのさまざまなコンポーネントにアプリケーションのモジュール化を可能にし、テスト可能性を念頭に置いて設計されています。 AngularJSのサービスは、中央の場所で再利用可能なロジックを定義する一般的なコンポーネントです。サービスをテストするとき、他のサービスにある依存関係は、モックオブジェクトに置き換える必要があります。 AngularJのコントローラーは注射できませんが、ルートロードまたはNGコントローラーディレクティブがコンパイルされたときに自動的にインスタンス化されます。コントローラーをテストするときは、手動でインスタンス化する必要があり、ビューがコンパイルされた後にスコープに追加されるオブジェクトを手動で作成してコントローラーに追加する必要があります。 AngularJのプロバイダーは、アプリケーションの開始前に作成する必要があるアプリケーション全体の構成のAPIを公開するために使用されます。プロバイダーをテストするには、モジュールをロードして準備する必要があります。依存関係をock笑する必要があり、コールバックをモジュールブロックに渡す必要があります。 AngularJSでの単位テストは難しい場合がありますが、アプリケーションの正確性を保証するため、時間の価値があります。 AngularJSにより、フレームワークを使用して記述された単位テストコードが簡単になります。
  • AngularJSは、テスト可能性を念頭に置いて設計されています。依存関係注射は、単体テストを容易にするフレームワークの顕著な特徴の1つです。 AngularJSは、アプリケーションをきれいにモジュール化し、コントローラー、ディレクティブ、フィルター、アニメーションなどのさまざまなコンポーネントに分割する方法を定義します。この開発モデルは、個々のピースが単独で機能し、アプリケーションが長期間にわたって簡単に拡大できることを意味します。拡張性とテスト能力が密接に関連するため、AngularJSコードを簡単にテストするのは簡単です。
  • 単体テストの定義に従って、テスト中のシステムは単独でテストする必要があります。したがって、システムが必要とする外部オブジェクトは、モックオブジェクトに置き換える必要があります。名前自体が言うように、模擬オブジェクトは実際のタスクを実行しません。むしろ、テスト中のシステムの期待を満たすために使用されます。モッキングの復習が必要な場合は、以前の記事の1つを参照してください。AngularJSテストでのモッキング依存関係を参照してください。 この記事では、AngularJSのテストサービス、コントローラー、プロバイダーに関する一連のヒントを共有します。コードスニペットはジャスミンを使用して記述されており、Karma Test Runnerで実行できます。この記事で使用されているコードをGitHub Repoからダウンロードできます。ここでは、テストの実行に関する指示も見つけることができます。

    テストサービス

    サービスは、AngularJSアプリケーションで最も一般的なコンポーネントの1つです。それらは、中央の場所で再利用可能なロジックを定義する方法を提供し、同じロジックを何度も繰り返す必要がないようにします。サービスのシングルトンの性質により、複数のコントローラー、ディレクティブ、さらには他のサービスで同じデータを共有することができます。

    サービスは、そのタスクを実行するために他のサービスのセットに依存できます。たとえば、Aという名前のサービスは、そのタスクを実行するためにサービスB、C、Dに依存します。サービスAのテスト中、依存関係B、C、およびDをモックに置き換える必要があります。

    $ Rootscopeや$ Parseなどの特定のユーティリティサービスを除き、通常、すべての依存関係をock笑します。 Jasmine.createspy()を使用して、テストで検査する必要がある方法(ジャスミンでは、模擬はスパイと呼ばれます)でスパイを作成します。

    次のサービスを考えてみましょう

    このサービスには1つの方法(showdialog)しかありません。この方法が受信する入力の値に応じて、依存関係($ windowまたはmodalsvc)として注入される2つのサービスの1つを呼び出します。

    angular<span>.module('services', [])
    </span>  <span>.service('sampleSvc', ['$window', 'modalSvc', function($<span>window, modalSvc</span>){
    </span>    <span>this.showDialog = function(message<span>, title</span>){
    </span>      <span>if(title){
    </span>        modalSvc<span>.showModalDialog({
    </span>          <span>title: title,
    </span>          <span>message: message
    </span>        <span>});
    </span>      <span>} else {
    </span>        $<span>window.alert(message);
    </span>      <span>}
    </span>    <span>};
    </span>  <span>}]);</span>
    これで、ShowDialogメソッドの動作をテストできます。メソッドのために書くことができる2つのテストケースは次のとおりです。

    タイトルがパラメーターが渡されない場合、アラートを呼び出します

    タイトルパラメーターとメッセージパラメーターの両方が存在する場合、showmodaldialogを呼び出します
    <span>var mockWindow, mockModalSvc, sampleSvcObj;
    </span><span>beforeEach(function(){
    </span>  <span>module(function($provide){
    </span>    $provide<span>.service('$window', function(){
    </span>      <span>this.alert= jasmine.createSpy('alert');
    </span>    <span>});
    </span>    $provide<span>.service('modalSvc', function(){
    </span>      <span>this.showModalDialog = jasmine.createSpy('showModalDialog');
    </span>    <span>});
    </span>  <span>});
    </span>  <span>module('services');
    </span><span>});
    </span>
    <span>beforeEach(inject(function($<span>window, modalSvc, sampleSvc</span>){
    </span>  mockWindow<span>=$window;
    </span>  mockModalSvc<span>=modalSvc;
    </span>  sampleSvcObj<span>=sampleSvc;
    </span><span>}));</span>

    次のスニペットには、これらのテストが表示されます
    • この方法にはテストするロジックはあまりありませんが、通常のWebアプリのサービスには通常、多くの機能が含まれています。このヒントに示されている手法を使用して、サービスへの参照をock笑して取得できます。サービステストでは、サービスの作成中に想定されていたあらゆるシナリオをカバーする必要があります。
    • 工場と価値は、同じ手法を使用してテストすることもできます。
    • コントローラーのテスト
    コントローラーをテストするためのセットアッププロセスは、サービスのセットアッププロセスとはまったく異なります。これは、コントローラーが注射できないため、ルートがロードされたときに自動的にインスタンス化されるか、NGコントローラーディレクティブがコンパイルされているためです。テストでビューが読み込まれていないため、テスト中のコントローラーを手動でインスタンス化する必要があります。

    コントローラーは一般にビューに結び付けられているため、コントローラーのメソッドの動作はビューに依存します。また、ビューがコンパイルされた後、いくつかの追加のオブジェクトがスコープに追加される場合があります。これの最も一般的な例の1つは、フォームオブジェクトです。テストを予想どおりに機能させるには、これらのオブジェクトを手動で作成してコントローラーに追加する必要があります。

    コントローラーは、次のタイプのいずれかを使用できます。
      $ scope
    • で使用されるコントローラー Controllerで構文
    • として使用される
    • コントローラー
    違いがわからない場合は、こちらについて詳しく読むことができます。いずれにせよ、これらの両方のケースについて説明します でコントローラーをテストします

    次のコントローラーを検討してください:

    このコントローラーをテストするには、$スコープオブジェクトとサービスの模擬オブジェクト(DataSVC)を渡すことにより、コントローラーのインスタンスを作成する必要があります。このサービスには非同期方法が含まれているため、前の記事で概説したモッキングプロミステクニックを使用してock笑する必要があります。

    次のスニペットはDataSVCサービスをock笑します:

    angular<span>.module('services', [])
    </span>  <span>.service('sampleSvc', ['$window', 'modalSvc', function($<span>window, modalSvc</span>){
    </span>    <span>this.showDialog = function(message<span>, title</span>){
    </span>      <span>if(title){
    </span>        modalSvc<span>.showModalDialog({
    </span>          <span>title: title,
    </span>          <span>message: message
    </span>        <span>});
    </span>      <span>} else {
    </span>        $<span>window.alert(message);
    </span>      <span>}
    </span>    <span>};
    </span>  <span>}]);</span>

    $ rotscope。$ new Methodを使用して、コントローラーの新しいスコープを作成できます。コントローラーのインスタンスを作成した後、この新しい$スコープにすべてのフィールドとメソッドがあります。

    コントローラーがフィールドとメソッドを$スコープに追加すると、それらが正しい値に設定されているかどうか、メソッドに正しいロジックがあるかどうかを確認できます。上記のサンプルコントローラーは、正規表現を追加して有効な番号を確認します。 正規表現の動作をテストするために仕様を追加しましょう:

    <span>var mockWindow, mockModalSvc, sampleSvcObj;
    </span><span>beforeEach(function(){
    </span>  <span>module(function($provide){
    </span>    $provide<span>.service('$window', function(){
    </span>      <span>this.alert= jasmine.createSpy('alert');
    </span>    <span>});
    </span>    $provide<span>.service('modalSvc', function(){
    </span>      <span>this.showModalDialog = jasmine.createSpy('showModalDialog');
    </span>    <span>});
    </span>  <span>});
    </span>  <span>module('services');
    </span><span>});
    </span>
    <span>beforeEach(inject(function($<span>window, modalSvc, sampleSvc</span>){
    </span>  mockWindow<span>=$window;
    </span>  mockModalSvc<span>=modalSvc;
    </span>  sampleSvcObj<span>=sampleSvc;
    </span><span>}));</span>

    コントローラーがデフォルト値のオブジェクトを初期化した場合、仕様内の値を確認できます。

    SaveDataメソッドをテストするには、BookDetailsとBookFormオブジェクトの値を設定する必要があります。これらのオブジェクトはUI要素にバインドされるため、ビューがコンパイルされた実行時に作成されます。すでに述べたように、Savedataメソッドを呼び出す前に、いくつかの値で手動でそれらを初期化する必要があります。
    <span>it('should show alert when title is not passed into showDialog', function(){
    </span>  <span>var message="Some message";
    </span>  sampleSvcObj<span>.showDialog(message);
    </span>
      <span>expect(mockWindow.alert).toHaveBeenCalledWith(message);
    </span>  <span>expect(mockModalSvc.showModalDialog).not.toHaveBeenCalled();
    </span><span>});
    </span>
    <span>it('should show modal when title is passed into showDialog', function(){
    </span>  <span>var message="Some message";
    </span>  <span>var title="Some title";
    </span>  sampleSvcObj<span>.showDialog(message, title);
    </span>
      <span>expect(mockModalSvc.showModalDialog).toHaveBeenCalledWith({
    </span>    <span>message: message,
    </span>    <span>title: title
    </span>  <span>});
    </span>  <span>expect(mockWindow.alert).not.toHaveBeenCalled();
    </span><span>});</span>

    次のスニペットはこの方法をテストします:

    angular<span>.module('controllers',[])
    </span>  <span>.controller('FirstController', ['$scope','dataSvc', function($scope<span>, dataSvc</span>) {
    </span>    $scope<span>.saveData = function () {
    </span>      dataSvc<span>.save($scope.bookDetails).then(function (result) {
    </span>        $scope<span>.bookDetails = {};
    </span>        $scope<span>.bookForm.$setPristine();
    </span>      <span>});
    </span>    <span>};
    </span>
        $scope<span>.numberPattern = <span>/<span>^\d*$</span>/</span>;
    </span>  <span>}]);</span>
    「コントローラーとして」のコントローラーをテストする

    syntax

    コントローラーを使用するコントローラーをテストするのは、$スコープを使用して構文をテストするよりも簡単です。この場合、コントローラーのインスタンスがモデルの役割を果たします。その結果、すべてのアクションとオブジェクトはこのインスタンスで利用できます。

    次のコントローラーを検討してください:

    このコントローラーを呼び出すプロセスは、前述のプロセスに似ています。唯一の違いは、$スコープを作成する必要がないことです。
    <span>module(function($provide){
    </span>  $provide<span>.factory('dataSvc', ['$q', function($q)
    </span>    <span>function save(data){
    </span>      <span>if(passPromise){
    </span>        <span>return $q.when();
    </span>      <span>} else {
    </span>        <span>return $q.reject();
    </span>      <span>}
    </span>    <span>}
    </span>    <span>return{
    </span>      <span>save: save
    </span>    <span>};
    </span>  <span>}]);
    </span><span>});</span>
    このインスタンスには、コントローラー内のすべてのメンバーとメソッドが追加されるため、インスタンス参照を使用してアクセスできます。

    以下のスニペットテスト上記のコントローラーに追加された番号パターンフィールド:

    Savedataメソッドのアサーションは同じままです。このアプローチの唯一の違いは、BookDetailsとBookformオブジェクトに値を初期化する方法です。

    次のスニペットには、スペックが表示されます:
    <span>beforeEach(inject(function($rootScope<span>, $controller, dataSvc</span>){
    </span>  scope<span>=$rootScope.$new();
    </span>  mockDataSvc<span>=dataSvc;
    </span>  <span>spyOn(mockDataSvc,'save').andCallThrough();
    </span>  firstController <span>= $controller('FirstController', {
    </span>    <span>$scope: scope, 
    </span>    <span>dataSvc: mockDataSvc
    </span>  <span>});
    </span><span>}));</span>
    angular<span>.module('services', [])
    </span>  <span>.service('sampleSvc', ['$window', 'modalSvc', function($<span>window, modalSvc</span>){
    </span>    <span>this.showDialog = function(message<span>, title</span>){
    </span>      <span>if(title){
    </span>        modalSvc<span>.showModalDialog({
    </span>          <span>title: title,
    </span>          <span>message: message
    </span>        <span>});
    </span>      <span>} else {
    </span>        $<span>window.alert(message);
    </span>      <span>}
    </span>    <span>};
    </span>  <span>}]);</span>

    テストプロバイダー

    プロバイダーは、アプリケーションの開始前に作成する必要があるアプリケーション全体の構成のAPIを公開するために使用されます。 AngularJSアプリケーションの構成フェーズが終了すると、プロバイダーとの相互作用が許可されます。したがって、プロバイダーは、構成ブロックまたは他のプロバイダーブロックでのみアクセスできます。注入ブロックを使用してプロバイダーインスタンスを取得することはできません。むしろ、モジュールブロックにコールバックを渡す必要があります。

    2番目のプロバイダー(別のプロバイダー)の定数(AppConstants)に依存する次のプロバイダーを考えてみましょう:

    <span>var mockWindow, mockModalSvc, sampleSvcObj;
    </span><span>beforeEach(function(){
    </span>  <span>module(function($provide){
    </span>    $provide<span>.service('$window', function(){
    </span>      <span>this.alert= jasmine.createSpy('alert');
    </span>    <span>});
    </span>    $provide<span>.service('modalSvc', function(){
    </span>      <span>this.showModalDialog = jasmine.createSpy('showModalDialog');
    </span>    <span>});
    </span>  <span>});
    </span>  <span>module('services');
    </span><span>});
    </span>
    <span>beforeEach(inject(function($<span>window, modalSvc, sampleSvc</span>){
    </span>  mockWindow<span>=$window;
    </span>  mockModalSvc<span>=modalSvc;
    </span>  sampleSvcObj<span>=sampleSvc;
    </span><span>}));</span>
    これをテストするには、まず依存関係をmock笑する必要があります。サンプルコードでこれを行う方法を見ることができます。

    プロバイダーをテストする前に、モジュールがロードされて準備が整っていることを確認する必要があります。テストでは、注入ブロックが実行されるか、最初のテストが実行されるまでモジュールの負荷が延期されます。いくつかのプロジェクトでは、モジュールをロードするために空の最初のテストを使用するいくつかのテストを見てきました。私はこのアプローチのファンではありません。テストでは何もしておらず、テストの総数にカウントを追加します。代わりに、空の注入ブロックを使用してモジュールをロードします。

    次のスニペットは参照を取得し、モジュールをロードします。

    参照がすべて揃ったので、プロバイダーで定義されたメソッドを呼び出してテストできます。

    結論
    <span>it('should show alert when title is not passed into showDialog', function(){
    </span>  <span>var message="Some message";
    </span>  sampleSvcObj<span>.showDialog(message);
    </span>
      <span>expect(mockWindow.alert).toHaveBeenCalledWith(message);
    </span>  <span>expect(mockModalSvc.showModalDialog).not.toHaveBeenCalled();
    </span><span>});
    </span>
    <span>it('should show modal when title is passed into showDialog', function(){
    </span>  <span>var message="Some message";
    </span>  <span>var title="Some title";
    </span>  sampleSvcObj<span>.showDialog(message, title);
    </span>
      <span>expect(mockModalSvc.showModalDialog).toHaveBeenCalledWith({
    </span>    <span>message: message,
    </span>    <span>title: title
    </span>  <span>});
    </span>  <span>expect(mockWindow.alert).not.toHaveBeenCalled();
    </span><span>});</span>

    単位テストは時々トリッキーになりますが、アプリケーションの正確性を保証するため、時間を費やす価値があります。 AngularJSを使用して、フレームワークを使用して記述されたコードを簡単にテストします。この記事が、アプリケーションのテストを拡張および強化するのに十分なアイデアを提供することを願っています。今後の記事では、コードの他の部分をテストする方法をさらに検討します。

    angularjsサービス、コントローラー、およびプロバイダーに関するユニットテストに関するよくある質問(FAQ)
    angular<span>.module('controllers',[])
    </span>  <span>.controller('FirstController', ['$scope','dataSvc', function($scope<span>, dataSvc</span>) {
    </span>    $scope<span>.saveData = function () {
    </span>      dataSvc<span>.save($scope.bookDetails).then(function (result) {
    </span>        $scope<span>.bookDetails = {};
    </span>        $scope<span>.bookForm.$setPristine();
    </span>      <span>});
    </span>    <span>};
    </span>
        $scope<span>.numberPattern = <span>/<span>^\d*$</span>/</span>;
    </span>  <span>}]);</span>
    ​​単位試験は、AngularJS開発の重要な側面です。これは、サービス、コントローラー、プロバイダーなどの個々のコンポーネントの機能を単独で検証するのに役立ちます。これにより、各コンポーネントがより大きなアプリケーションに統合される前に、予想どおりに機能することが保証されます。ユニットテストは、開発プロセスの早い段階でバグを特定するのに役立ち、それらを簡単に修正しやすくなります。また、コードの品質を維持し、アプリケーションの全体的な信頼性を向上させるのにも役立ちます。 ​​AngularJSのテスト環境をセットアップするには、いくつかのステップが含まれます。まず、ジャスミンやカルマなどの必要なテストツールをインストールする必要があります。 Jasmineは、JavaScriptコードをテストするための動作駆動型開発フレームワークであり、Karmaは実際のブラウザでテストを実行するテストランナーです。これらのツールをインストールした後、テストケースを個別のテストファイルで作成し、Karmaを使用して実行できます。依存関係をock笑します。 Jasmineは、「Spyon」と呼ばれる関数を提供し、模擬関数を作成し、その呼び出しを追跡できます。この関数を使用して、サービスの依存関係をmockし、テスト用に分離できます。モックをセットアップした後、サービスのメソッドを呼び出し、ジャスミンの「期待」関数を使用して出力を検証できます。コントローラーのメソッドとプロパティのテスト。 AngularJSが提供する$コントローラーサービスを使用して、コントローラーのインスタンスを作成できます。インスタンスを作成した後、その方法を呼び出して、コントローラーの範囲に対する効果を確認できます。また、サービスをock笑し、メソッドへの呼び出しを検証することにより、コントローラーのサービスとの対話をテストすることもできます。

    AngularJSプロバイダーをテストする方法は?プロバイダーをテストに注入し、その依存関係をock笑し、その方法をテストできます。ただし、プロバイダーには、サービスのインスタンスを返す「$ get」と呼ばれる特別な方法があります。この方法は、呼び出して返された値をチェックすることで個別にテストできます。コンポーネントへの依存関係。テストでは、この機能を使用して、テスト中のコンポーネントに依存関係のモックバージョンを注入できます。これにより、コンポーネントを隔離し、その依存関係とは独立してテストできます。Angularjsテストで非同期操作を処理するにはどうすればよいですか? ​​

    AngularJSテストでの非同期操作は、$ qサービスとJasmineが提供する「完了」関数を使用して処理できます。 $ Qサービスを使用すると、テストで解決または拒否できる約束を作成できます。 「完了」関数は、非同期操作が完了したことを示すために呼び出すことができます。 。 AngularJSが提供する$コンパイルサービスを使用して、ディレクティブのインスタンスを作成できます。インスタンスを作成した後、jQueryのような方法を使用して操作し、範囲への影響を確認できます。それらをock笑することで対処することができます。依存関係のモックバージョンを作成し、テスト中のコンポーネントに注入できます。これにより、依存関係の動作を制御し、テストのためにコンポーネントを分離できます。

以上がAngularJSの単体テスト:サービス、コントローラー、プロバイダーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。