2016-08-31 25 views
5

Tôi khá mới với Angular và tôi đang làm việc để kiểm tra dịch vụ Angular chạy dịch vụ cấp API kết thúc một loạt các cuộc gọi tới dịch vụ REST. Bởi vì nó đang làm việc với các yêu cầu HTTP, cả hai phần của dịch vụ đang làm việc với các lời hứa và dường như nó hoạt động tốt, nhưng tôi gặp khó khăn trong việc kiểm tra các hành vi đã hứa.Thử nghiệm Jasmine cho dịch vụ Angular không giải quyết cuộc gọi hoãn lại

Phần liên quan của mã dịch vụ của tôi (hiển nhiên đơn giản hóa) trông như thế này:

angular.module('my.info') 
.service('myInfoService', function (infoApi, $q) { 
    infoLoaded: false, 
    allInfo: [], 
    getInfo: function() { 
     var defer = $q.defer(); 
     if (infoLoaded) { 
      defer.resolve(allInfo); 
     } else { 
      infoApi.getAllInfo().then(function (newInfo) { 
       allInfo = newInfo; 
       infoLoaded = true; 
       defer.resolve(allInfo); 
      }); 
     } 
     return defer.promise; 
    } 
}); 

Khi tôi đang thiết lập mô hình của tôi, tôi có một cái gì đó như thế này:

describe("Info Service ", 
    function() { 
     var infoService, infoRequestApi, $q; 
     beforeEach(module("my.info")); 
     beforeEach(function() { 
      module(function($provide) { 
       infoRequestApi = { 
        requestCount: 0, 
        getAllInfo: function() { 
         var defer = $q.defer(); 
         this.requestCount++; 
         defer.resolve([ "info 1", "info 2" ]); 
         return defer.promise; 
        } 
       }; 
       $provide.value("infoApi", infoRequestApi); 
      }); 
      inject(function(_myInfoService_, _$q_) { 
       infoService = _myInfoService_, 
       $q = _$q_; 
      }); 
     }); 

     it("should not fail in the middle of a test", function(done) { 
      infoService.getInfo().then(function(infoResult) { 
        // expectation checks. 
        expect(true).toBeTrue(); 
       }).finally(done); 
     }); 
    }); 

Bất kỳ kiểm tra đồng bộ vượt qua tốt, nhưng khi tôi cố gắng chạy bất kỳ bài kiểm tra nào như thế này, tôi nhận được thông báo cho biết: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

Dường như là có điều gì đó về cách mà Angular.Moc ks xử lý kết quả trì hoãn là làm cho nó thất bại. Khi tôi trải qua bài kiểm tra, biến số defer của đối tượng giả được đặt chính xác, nhưng tuyên bố then trong dịch vụ sẽ không bao giờ được gọi. Tôi làm sai ở đâu?

Trả lời

3

ngắn trả lời

Bạn phải khởi động một chu kỳ tiêu hóa. Bạn có thể làm điều đó với $rootScope.$apply().

it("should not fail in the middle of a test", inject(function($rootScope) { 
    var actualResult = null; 
    infoService.getInfo() 
    .then(function(infoResult) { actualResult = infoResult; }); 
    $rootScope.$apply(); 
    expect(actualResult).toEqual(["info 1", "info 2"]); 
})); 

Note

tôi sẽ không cố gắng để tạo ra một dịch vụ infoRequestApi giả theo cách bạn đang làm nó. Bạn cũng nên tiêm dịch vụ đó và theo dõi các chức năng của nó. Ví dụ, một cái gì đó như thế này:

it("should not fail in the middle of a test", inject(function($rootScope, infoApi, $q) { 
    var deferred = $q.defer(); 
    spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise); 
    var actualResult = null; 
    var expectedResult = ["info 1", "info 2"]; 

    infoService.getInfo() 
    .then(function(infoResult) { actualResult = infoResult; }); 

    deferred.resolve(expectedResult); 
    $rootScope.$apply(); 
    expect(actualResult).toBe(expectedResult); 
})); 

refactored

Ngoài ra, mã của bạn có thể được đơn giản hóa một chút (chưa được kiểm tra, nhưng gần với những gì tôi mong đợi để xem).

angular.module('my.info') 
    .service('myInfoService', function (infoApi, $q) { 
    return { 
     infoLoaded: false, 
     allInfo: [], 
     getInfo: function() { 
     var self = this; 
     return this.infoLoaded ? $q.resolve(this.allInfo) : 
      infoApi.getAllInfo().then(function (newInfo) { 
      self.allInfo = newInfo; 
      self.infoLoaded = true; 
      }); 
    } 
    }; 
}); 

describe("Info Service ", function() { 
    var infoService, infoApi, $q, $rootScope; 

    beforeEach(module("my.info")); 
    beforeEach(inject(function(_myInfoService_, _$q_ _$rootScope_, _infoApi_) { 
    infoService = _myInfoService_, 
    $q = _$q_; 
    $rootScope = _$rootScope_; 
    infoApi = _infoApi_; 
    }); 

    it("should do something", function() { // update message 
    var deferred = $q.defer(); 
    spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise); 
    var actualResult = null; 
    var expectedResult = ["info 1", "info 2"]; 

    infoService.getInfo() 
     .then(function(infoResult) { actualResult = infoResult; }); 

    deferred.resolve(expectedResult); 
    $rootScope.$apply(); 
    expect(actualResult).toBe(expectedResult); 
    }); 
}); 
+0

Cảm ơn bạn đã tăng gấp đôi, cả câu trả lời hay và đề xuất tái cấu trúc. Tôi nghi ngờ rằng cách tiếp cận chế nhạo là một chút dài gió! Vấn đề duy nhất tôi có bây giờ là có vẻ như nếu tôi có một vài lớp dịch vụ, có vẻ như tôi cần phải tiêm một mô hình cho mọi nhà xây dựng theo đúng cách, nhưng điều này là gọn gàng hơn và thành ngữ hơn. – glenatron

+0

@glenatron Không sao cả. Bạn chỉ cần giả lập các phụ thuộc được sử dụng trong dịch vụ đang được kiểm tra. Bạn không cần phải giả lập phụ thuộc của họ, do đó, các câu hỏi của lớp là tranh luận. –

+0

Bạn đã chính xác, tôi đã thực sự gặp sự cố với thử nghiệm Chutzpah cho Visual Studio, điều này đã gây ra lỗi thất bại. Các bài kiểm tra tương tự cũng hoạt động tốt dưới các trình chạy thử khác. – glenatron

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