0

我試圖讓使用注入組件的服務的Github的API調用 - 是的,我使用AngularJS 1.5.3。AngularJS /噶/茉莉花 - 服務電話沒有返回值

在單元測試中,我沒有收到回值(當我在瀏覽器中運行它的功能不工作)。我不確定自己做錯了什麼,希望有人能指引我走向正確的方向。

這裏的錯誤: enter image description here

main.component.js

(function(){ 
    angular.module("app").component("mainComponent", { 
     templateUrl: "/templates/main.component.html", 
     controllerAs: "vm", 
     controller: function(APIFactory, UserFactory, $state){ 
      const vm = this; 

      vm.searchGithub = function(){ 
       APIFactory.getAPI(vm.searchText).then(function(res){ 
        res.status !== 200 ? $state.go("404", {errorData: res.data }) : (
         vm.User = new UserFactory.User(res.data), 
         $state.go("profile", {userData: vm.User}) 
        ); 
       }) 
       .catch(function(err){ 
        $state.go("fourOFour"); 
       }); 
      }; 
     } 
    }); 
})(); 

main.component.spec.js

describe("Main Component", function(){ 
    var mainComponent, APIFactory, UserFactory, $httpBackend, $q, $state, $rootScope; 

    const addy = "https://api.github.com/users/"; 

    beforeEach(angular.mock.module("app")); 

    beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){ 
     APIFactory = _APIFactory_; 
     UserFactory = _UserFactory_; 
     $httpBackend = _$httpBackend_; 
     $state = _$state_; 
     $q = _$q_; 
     $rootScope = _$rootScope_; 
     $rootScope.$new(); 
     mainComponent = _$componentController_("mainComponent", { $scope : {} }); 
    })); 

    describe("Checking if the searchGithub() worked correctly", function(){ 
     var result; 

     beforeEach(function(){ 
      spyOn(mainComponent, "searchGithub").and.callThrough(); 
      spyOn(APIFactory, "getAPI").and.callThrough(); 
      result = {}; 
     }); 

     it("should make a call to UserFactory", function(){ 
      mainComponent.searchText = "someName"; 
      expect(mainComponent.searchText).toBeDefined(); 

      // RESPONSE_SUCCESS does exist, I've omitted it. 
      $httpBackend.whenGET(addy + mainComponent.searchText).respond(200, $q.when(RESPONSE_SUCCESS)); 

      // This is where I expect something to work 

      APIFactory.getAPI(mainComponent.searchText).then(function(res){ 
       result = res; 
      }); 

      $httpBackend.flush(); 

      expect(APIFactory.getAPI).toHaveBeenCalledWith(mainComponent.searchText); 
      expect(mainComponent.User).toBeDefined(); 
     }); 
    }); 


}); 
+1

這裏是一個方法論的問題,而不是關注你混合所有單位某些特定裝置上的 - 控制器,服務和$ httpBackend - 成一個大的混亂。當不順心的事,你不這樣做。知道它在哪一點失敗。如果你正在測試一家公司在這裏ntroller,模擬/存根其他所有服務(包括$州)。 – estus

+0

更改'期望(mainComponent.User).toBeDefined();''到期望(mainComponent.User).not.toBeDefined();'。 – georgeawg

+0

@estus - 我很欣賞這個好建議。你能看看我的答案,看看你是否認爲這是一個好的解決方案? –

回答

0

原來這就是我來提供解決方案。如果有人想給我一個更好的解決方案,我想出點想法。

首先,我做了兩個模擬考試,然後我其注射到mainComponent,以及對我的嘲笑APIFactoryMock.getAPI功能的間諜:

const APIFactoryMock = { 
    getAPI: function(){} 
}; 

const UserFactoryMock = { 
    User: function(data){ 
     return { 
      login: data.login, 
      id: data.id, 
      avatar_url: data.avatar_url, 
      html_url: data.html_url, 
      followers: data.followers, 
      following: data.following, 
      public_repos: data.public_repos, 
      public_gists: data.public_gists, 
      created_at: data.created_at, 
      updated_at: data.updated_at, 
      name: data.name, 
      company: data.company, 
      blog: data.blog, 
      location: data.location, 
      bio: data.bio, 
      hireable: data.hireable, 
      email: data.email, 
      links: { 
       followers_url: data.followers_url, 
       following_url: data.following_url, 
       subscriptions_url: data.subscriptions_url, 
       repos_url: data.repos_url, 
       organizations_url: data.organizations_url 
      } 
     } 
    } 
}; 

beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){ 
    APIFactory = _APIFactory_; 
    UserFactory = _UserFactory_; 
    $httpBackend = _$httpBackend_; 
    $state = _$state_; 
    $q = _$q_; 
    $rootScope = _$rootScope_; 
    $rootScope.$new(); 
    spyOn(APIFactoryMock, "getAPI").and.returnValue(RESPONSE_SUCCESS); 
    bindings = { APIFactory: APIFactoryMock, UserFactory: UserFactoryMock, $state: $state }; 
    mainComponent = _$componentController_("mainComponent", { $scope : {} }, bindings); 
})); 

然後我寫的嘲弄測試:

it("should make a call to UserFactory", function(){ 
     mainComponent.searchText = "someName"; 
     expect(mainComponent.searchText).toBeDefined(); 


     mainComponent.searchGithub(mainComponent.searchText); 
     $httpBackend.whenGET(addy + mainComponent.searchText).respond(200, $q.when(RESPONSE_SUCCESS)); 

     $httpBackend.flush(); 

     mainComponent.User = UserFactoryMock.User(RESPONSE_SUCCESS.data); 

     expect(mainComponent.searchGithub).toHaveBeenCalledWith(mainComponent.searchText); 
     expect(mainComponent.User).toBeDefined(); 
     expect(mainComponent.User.id).toEqual(666); 
    }); 
0

在上述答案中,您正手動在測試用例中撥打UserFactoryMock.User,這將創建一個用戶對象。

但要正確地測試功能,以應檢查UserFactory.User時調用APIFactory.getAPI是成功的(無需對UserFactory.User來電測試用例手動調用。

我建議修改你的測試用例的東西如下圖所示:

describe("Main Component", function(){ 
var mainComponent, APIFactory, UserFactory, $httpBackend, $q, $state, $rootScope; 

const addy = "https://api.github.com/users/"; 

beforeEach(angular.mock.module("app")); 

beforeEach(inject(function(_APIFactory_, _UserFactory_, _$httpBackend_, _$state_, _$q_, _$rootScope_, _$componentController_){ 
    APIFactory = _APIFactory_; 
    UserFactory = _UserFactory_; 
    $httpBackend = _$httpBackend_; 
    $state = _$state_; 
    $q = _$q_; 
    $rootScope = _$rootScope_; 
    var scope = $rootScope.$new(); 
    var bindings = { APIFactory: APIFactory, UserFactory: UserFactory, $state: $state }; 
    mainComponent = _$componentController_("mainComponent", { $scope : scope }, bindings); 
})); 

describe("Checking if the searchGithub() worked correctly", function(){ 
    var result; 

    beforeEach(function(){ 
     spyOn(mainComponent, "searchGithub").and.callThrough(); 
     spyOn(APIFactory, "getAPI").and.callFake(function() { 
      var def = $q.defer(); 
      def.resolve(RESPONSE_SUCCESS); 
      return def.promise; 
     }); 
     spyOn(UserFactory, "User").and.callFake(function() { 
      var user = { id: 666, .... }; 
      return user; 
     }); 
    }); 

    it("should make a call to UserFactory", function(){ 
     mainComponent.searchText = "someName"; 
     $rootScope.$apply(); 
     expect(mainComponent.searchText).toBeDefined(); 

     mainComponent.searchGithub(); // Call the same way as it works in the code actually. 

     $rootScope.$apply(); 

     //No manual call to 'UserFactory.User' or 'APIFactory.getAPI'. The call to 'APIFactory.getAPI' is resolved/succeeds, hence a call to 'UserFactory.User' is made and the same is tested 
     expect(APIFactory.getAPI).toHaveBeenCalledWith(mainComponent.searchText); 
     expect(UserFactory.User).toHaveBeenCalledWith(RESPONSE_SUCCESS.data); 
     expect(mainComponent.User).toBeDefined(); 
     expect(mainComponent.User.id).toEqual(666); 
    }); 
}); 


}); 
+0

@ les-paul你可以檢查一下上面的答案嗎? – Abhishek