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