【问题标题】:Testing a loader in angular js在 Angular js 中测试加载器
【发布时间】:2014-05-08 19:24:46
【问题描述】:

这是一个带有加载器的 $resource 测试

describe('Service: MultiCalculationsLoader', function(){

  beforeEach(module('clientApp'));

  var MultiCalculationLoader,
    mockBackend,
    calculation;

  beforeEach(inject(function (_$httpBackend_, Calculation, _MultiCalculationLoader_) {
    MultiCalculationLoader = _MultiCalculationLoader_;
    mockBackend = _$httpBackend_;
    calculation = Calculation;
  }));

  it('should load a list of calculation from a user', function(){
    mockBackend.expectGET('/api/user/600/calculation').respond([{id:5}]);

     var calculations;
     var mockStateParams = {
       userId: 600
     };
    var promise = new MultiCalculationLoader(mockStateParams);

    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual([{id:5}]);
  });

});

当我运行测试时,我收到以下错误:

Expected [ { id : 5 } ] to equal [ { id : 5 } ].
Error: Expected [ { id : 5 } ] to equal [ { id : 5 } ].
    at null.<anonymous> 

我不明白。这两个数组对我来说是一样的。有什么想法吗?

更新 这是实现:

 .factory('Calculation', function ($resource) {
    return $resource('/api/user/:userId/calculation/:calcId', {'calcId': '@calcId'});
  })
  .factory('MultiCalculationLoader', function (Calculation, $q) {
    return function ($stateParams) {
      var delay = $q.defer();
      Calculation.query( {userId: $stateParams.userId},function (calcs) {
        delay.resolve(calcs);
      }, function () {
        delay.reject('Unable to fetch calculations');
      });
      return delay.promise;
    };
  })

【问题讨论】:

  • @KhanhTO Yeha 但它在我的开发环境中不起作用。
  • 您能展示一下您的MultiCalculationLoader 是如何实现的吗?
  • 实施有效。只是我的测试不起作用。
  • 我只是怀疑您的MultiCalculationLoader 中存在导致测试失败的问题

标签: javascript angularjs karma-jasmine


【解决方案1】:

您期望的网址与实际网址不同。我猜你需要这样的东西:

it('should load a list of calculation from a user', function(){
    //remove the 's' from 'calculations'
    mockBackend.expectGET('/api/user/600/calculation').respond([{id:5}]);

    var calculations;
    var promise = MultiCalculationLoader({userId:600}); //userId = 600
    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual([{id:5}]);
  });

还有一个问题是angular会自动在响应中添加2个属性:

http://plnkr.co/edit/gIHolGd85SLswzv5VZ1E?p=preview

这有点像:AngularJS + Jasmine: Comparing objects

当角度将响应转换为资源对象时,这确实是角度 $resource 的问题。为了验证来自 $resource 的响应,您可以尝试angular.equals

expect(angular.equals(calculations,[{id:5},{id:6}])).toBe(true);

http://plnkr.co/edit/PrZhk2hkvER2XTBIW7yv?p=preview

您还可以编写自定义匹配器:

beforeEach(function() {
    jasmine.addMatchers({
      toEqualData: function() {
        return {
          compare: function(actual, expected) {
            return {
              pass: angular.equals(actual, expected)
            };
          }
        };
      }
    });
  });

并使用它:

expect(calculations).toEqualData([{id:5},{id:6}]);

http://plnkr.co/edit/vNfRmc6R1G69kg0DyjZf?p=preview

【讨论】:

  • 是不是有点乱?也许我完全不在这里,但使用 angular.toJson 怎么样?我认为这会从数组中删除“垃圾”?
  • @user1572526:我发现我们可以使用angular.equalsangular.equals 会在测试时去掉 angular 的函数和内部实现细节(比如 hashkey)
  • @user1572526:您还可以编写自定义匹配器。查看更新的答案
【解决方案2】:

当您只想检查是否相等时,Jasmine 相等选择器有时可能过于具体。

在比较对象或数组时,我从未见过使用 toEqual() 方法,但使用 toBe() 方法进行定义。

尝试将 toEqual() 替换为 toMatch()。

在单元测试中,我建议使用一个常量值,您可以在响应和 matchers/equal/toBe's 中传递该值。

describe('Service: MultiCalculationsLoader', function(){

  beforeEach(module('clientApp'));

  var MultiCalculationLoader,
    mockBackend,
    calculation,
    VALUE = [{id:5}];

  beforeEach(inject(function (_$httpBackend_, Calculation, _MultiCalculationLoader_) {
    MultiCalculationLoader = _MultiCalculationLoader_;
    mockBackend = _$httpBackend_;
    calculation = Calculation;
  }));

  it('should load a list of calculation from a user', function(){
    mockBackend.expectGET('/api/user/600/calculations').respond(VALUE);

    var calculations;
    var promise = MultiCalculationLoader();
    promise.then(function(res){
      calculations = res
    });

    expect(calculations).toBeUndefined();

    mockBackend.flush();

    expect(calculations).toEqual(VALUE);
  });

});

使用这种方法,我认为 .toEqual 会真正起作用。

我们的方法:

块前:

httpBackend.when('JSONP', PATH.url + 'products?callback=JSON_CALLBACK&category=123').respond(CATEGORIES[0]);

测试:

describe('Category Method', function () {

        it('Should return the first category when the method category is called', function () {
            var result = '';

            service.category(123).then(function(response) {
                result = response;
            });

            httpBackend.flush();
            expect(result).toEqual(CATEGORIES[0]);

        });
    });

【讨论】:

  • 不适用于常量值。但它确实适用于 toMatch()。谢谢!
  • hmmm 很奇怪 - 这是我们在单元测试中采用的确切方法...尝试返回 VALUE[0] 并测试是否相等。
  • 可能与 expectGET 与 when 方法以及它们如何返回数据有关......
  • "toMatch" 似乎可以接受任何东西。所以它没有用。回到原点。还有其他想法吗?
  • 你有 3 个选择 - toMatch、toBe、toEqual
【解决方案3】:

你可以尝试用 toEqualData() 改变 toEqual()

expect(calculations).toEqualData([{id:5}]);

【讨论】:

  • 找不到“toEqualData”函数?
猜你喜欢
  • 1970-01-01
  • 2015-11-07
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-17
相关资源
最近更新 更多