【问题标题】:Angular unit test factory that uses http request使用 http 请求的 Angular 单元测试工厂
【发布时间】:2017-07-06 14:44:06
【问题描述】:

我正在开发一个带有 karma/Jasmine 测试框架的 Angular js 应用程序,我需要测试一个返回 http 承诺但它总是返回未定义的工厂

这是我的工厂

angular.module('GithubUsers').factory('Users',['$http','$q',function($http,$q){
  return{
    getAllUsers:function(){
      var defered= $q.defer();
      $http({
        url:'https://api.github.com/users',
        method:'GET'
      }).then(function(users){
        defered.resolve(users.data);
      },function(err){
        defered.reject(err);
      })
      return defered.promise;
    }
  }
}])

这是我的测试

更新感谢您的回答,我将代码修改为以下内容,但没有收到此错误

可能未处理的拒绝:{"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback" ,"url":"https://api.github.com/users?since=1","headers":{"Accept":"application/json, text/plain, /"},"cached":false},"statusText" :""} 抛出

describe('Test Users Factory',function(){
  var $controller,
  Users,
  $rootScope,
  $httpBackend,
  $q;
  beforeEach(module('GithubUsers'));
  beforeEach(inject(function(_$controller_,_Users_,_$rootScope_,_$httpBackend_,_$q_){
    $controller = _$controller_;
    Users = _Users_;
    $rootScope= _$rootScope_;
    $httpBackend=_$httpBackend_;
    
   
  }))
  
  it('should get users',function(){
   
    var result;

    $httpBackend.whenGET('https://api.github.com/users?since=1').respond(function(){
       return {data:[{id:2}],status:200};
    })
    Users.getAllUsers().then(function(res){
      result = res;
    });
    $httpBackend.flush();
    $rootScope.$digest()
    expect(result).toBeTruthy();
  })
})

提前致谢!

【问题讨论】:

    标签: angularjs unit-testing karma-jasmine


    【解决方案1】:

    我认为您需要将一个函数传递给 whenGET().respond(),该函数返回一个 包含 3 个项目的数组

    也许,你可以试试这样的:

     beforeEach(angular.mock.inject(function (User, $httpBackend, $http) {
        ...
        this.withOKUsers = function() {
                var i1 = new User();
                i1.id = 10;
                return [200, JSON.stringify([ i1]), {}];
        } ...
    }));
    ...    
    it('should get users',function(){
    $httpBackend
        .whenGET('https://api.github.com/users')
        .respond(this.withOKUsers);
    
    Users.getAllUsers().then(function(res){
      result = res;
    });    
    
    $httpBackend.flush(); 
    expect(result).not.toBeNull();
    ...
    

    (我更喜欢在 it() 子句之外安排规范以提高可读性)

    【讨论】:

    • 感谢您的回复,但不幸的是它对我没有用
    • 确实忘了添加flush()方法。总是在 then 回调和您的期望之间刷新
    • 你试过在响应函数中返回 [200, JSON.stringify()...] 吗?我认为不需要摘要,这里
    【解决方案2】:

    您在调用测试方法后缺少 $httpBackend.flush(); 调用。它将调用成功/错误,或者然后正确地分解并解决 $q 的承诺。对于更多测试,我会将 $httpBackend.whenGET 分别移动到每个测试用例中,以便以后可以针对每个用例进行验证,但这只是我个人的意见。

    我觉得你在一个测试中混合了一个 $controller 和一个工厂有点可疑。我建议拆分它们,并在控制器测试中检查对服务方法的调用,并在工厂测试本身中执行 $httpBackend 的东西。

    下面我将您的测试粘贴到我的更正中。它现在对我有用:

    describe('Test Users Factory', function () {
    var Users,
    $rootScope,
    $httpBackend,
    $q;
    beforeEach(module('app.utils'));
    beforeEach(inject(function (_Users_, _$rootScope_, _$httpBackend_, _$q_) {
        Users = _Users_;
        $rootScope = _$rootScope_;
        $httpBackend = _$httpBackend_;
    }));
    
    afterEach(function () {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });
    
    it('should get users', function () {
        var result;
    
        $httpBackend.when('GET', "https://api.github.com/users").respond({ data: [{ id: 2 }], status: 200 });
    
        Users.getAllUsers().then(function (res) {
            result = res;
            expect(result).toBeTruthy();
        });
    
    
        $httpBackend.flush();
        $rootScope.$digest();
    });
    

    重要提示: 1)afterEach - 检查您的通话后是否没有待处理的请求 2)您的网址与参数 ?since=1 不同。但是您没有在代码中将其作为参数提供,所以我不明白您为什么添加此参数。 也许可以考虑用 url 和参数连接字符串?

    【讨论】:

    • 非常感谢您的澄清,之前我不知道flush 功能,请您查看我更新的问题
    猜你喜欢
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多