0

私たちが構築しているAngularアプリに非常に奇妙な問題があります。以下のように定義されたリソースからデータをロードするたびに (作成できる最も単純な例)、データバインディングに使用できるデータを取得します (例: ng-repeat='message in messages' または {{message.id}} として) )ただし、配列またはオブジェクトとしてアクセスしてjavascriptから読み取ることはできません(get({id:myId})またはquery()を使用したかどうかによって異なります)。

それを繰り返しても、$get、$query、$save などのキーしか得られませんが、実際のデータは得られません。

app.factory('Message', ['$resource', function($resource) {
    return $resource('MY_URL/messages/:id', {id: '@id'});
}]);

app.service('messageService', ['$rootScope', 'Message', function($rootScope, Message) {
    var messages = Message.query();
    var selectedMessage = null;

    var service = {};

    service.get = function(id) {
                    // Problem A (see below for details)
        if (arguments.length === 1) return Message.get({id: id});
        else return messages;
    };

var MenuCtrl = function($scope, Project, messageService, otherService) {
    $scope.projects = Project.query();
    $scope.messages = messageService.get();

    // Problem B (details below)
};

問題 A では、既にフェッチされたコレクションから単一の要素を返すことができるようにしたいのですが、データの準備が整う前に発生した呼び出しを処理する方法が必要です。

問題 B では、フェッチしたデータの一部を処理し、結果を「otherService」に渡したいと考えていますが、データの準備ができるまでこれを遅らせる方法が必要です。

4

1 に答える 1

1

私はこの問題が単体テストで発生するのを見ただけで、それを回避する方法は、モック $httpBackend を「フラッシュ」することです。

APIドキュメントによると:

本番環境で使用される $httpBackend は、常に非同期でリクエストに応答します。単体テストでこの動作を保持すると、非同期の単体テストを作成する必要があり、これは作成、追跡、保守が困難です。同時に、テスト中のコードの実行が変更されるため、テスト モックは同期的に応答できません。このため、モック $httpBackend には flush() メソッドがあり、テストが保留中のリクエストを明示的にフラッシュできるため、バックエンドの非同期 API を保持しながら、テストを同期的に実行できます。

いくつかのコンテキストの例を次に示します。

// define a resource within a service
angular.module('app.services', ['ngResource'])
  .factory('Message', function ($resource) {
    var url = ...
      , params = ...
      , actions = ...;

    return $resource(url, params, actions);
  }

// Query the resource in a controller
function MessagesCtrl ($scope, $routeParams, Message) {
  $scope.messages = Message.query();
}

// unit test with a mocked backend
describe('MessagesCtrl', function() {
  var scope, ctrl, $httpBackend, messages;

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

    messages = [
      {
        id: '1',
        text: 'foo',
      }, {
        id: '2',
        text: 'foo',
      }
    ]

    $httpBackend.expectGET('/api/messages').respond(messages);
    ctrl = $controller('MessagesCtrl', {$scope: scope});
  }));

  it('should get a list of messages', function () {

    // THE NEXT LINE WILL SOLVE THE PROBLEM
    $httpBackend.flush();

    expect(scope.message).toEqualData(message);
  });
});
于 2012-11-23T18:40:50.957 に答える