如何使用Sinon

时间:2016-05-20 06:38:14

标签: angularjs unit-testing promise mocha sinon

我在测试控制器的价值时遇到了麻烦,这些价值是在服务返回的承诺范围内设定的。我使用Sinon来存根服务(Karma运行测试,Mocha作为框架,Chai用于断言)。

我对快速解决方案的兴趣不如我理解问题。我已经阅读了很多内容,我在代码和测试下面有一些笔记。

这是代码。

.controller('NavCtrl', function (NavService) {
  var vm = this;
  NavService.getNav()
    .then(function(response){
      vm.nav = response.data;
    });
})

.service('NavService', ['$http', function  ($http) {
  this.getNav = function () {
    return $http.get('_routes');
  };
}]);

以下是测试:

describe('NavCtrl', function () {

  var scope;
  var controller;
  var NavService;
  var $q;

  beforeEach(module('nav'));

  beforeEach(inject(function($rootScope, $controller, _$q_, _NavService_){
    NavService = _NavService_;
    scope = $rootScope.$new();
    controller = $controller;
  }));

  it('should have some data', function () {

    var stub = sinon.stub(NavService, 'getNav').returns($q.when({
      response: {
        data: 'data'
      }
    }));

    var vm = controller("NavCtrl", {
      $scope: scope,
      NavService: NavService
    });

    scope.$apply();

    stub.callCount.should.equal(1);
    vm.should.be.defined;
    vm.nav.should.be.defined;

  });

});

正在调用存根,即测试通过,并且vm已定义,但vm.nav从不获取数据,测试失败。我认为,如何处理违约的承诺是罪魁祸首。一些说明:

  • 根据reading elsewhere,我正在调用scope.$apply来设置值,但由于范围未注入原始控制器,我不是积极的,将做到这一点。此article指向angular docs on $q

  • 另一篇文章推荐using $timeout,因为"实际完成了承诺"。该文章还建议使用" sinon-as-promise,"我上面没做过的事情。我试过了,但没有看到差异。

  • 此Stack Overflow回答使用scope.$root.$digest()因为"如果您的范围对象的值来自promise结果,则需要调用范围。$ root。$ digest() &#34 ;.但同样,同样的测试失败。而且,这可能是因为我没有使用范围。

  • 至于保留承诺,我也尝试了sinon sandbox way,但结果是一样的。

  • 我尝试使用$scope重写测试,以确保它不是vm style的问题,但测试仍然失败。

最后,我可能是错的:存根和承诺可能不是问题,它是我错过的不同和/或明显的东西。

非常感谢任何帮助,如果我能澄清以上任何内容,请告诉我。

2 个答案:

答案 0 :(得分:1)

抱歉,您可以快速解决所有问题:

var stub = sinon.stub(NavService, 'getNav').returns($q.when({
  response: {
    data: 'data'
  }
}));

您的承诺已解决为包含response.data的对象而不只是data 通过代码https://plnkr.co/edit/GL1Xuf?p=preview

查看此插件

扩展答案

我经常陷入同样的​​陷阱。所以我开始分别定义从方法返回的结果。然后,如果该方法是异步的,我将此结果包装在像$q.when(stubbedResult)这样的承诺中,这允许我轻松地对实际结果运行期望,因为我将存根结果保存在变量中,例如。

it('Controller should have some data', function () {

    var result = {data: 'data'};
    var stub = sinon.stub(NavService, 'getNav').returns($q.when(result));

    var vm = controller(/* initController */);

    scope.$apply();

    stub.callCount.should.equal(1);
    vm.nav.should.equal(result.data)
})

另外一些测试调试技巧会派上用场。最简单的方法是在控制台上转储一些数据,以检查某些地方返回的内容。当然,使用实际的调试器是可取的。

如何快速捕捉到这些错误:

    1. $rootScope.apply()行(就在执行之前)设置断点
    1. 在控制器的NavService.getNav().then处理程序中放置一个断点,以查看它是否被调用以及它被调用的内容
    1. 继续调试器以执行$rootScope.$apply()行。现在调试器应该达到上一步设置的断点 - 那就是它。

答案 1 :(得分:0)

我认为你应该使用chai-as-promised

然后从诸如

之类的承诺中断言
  doSomethingAsync().should.eventually.equal("foo");

或者使用async await

 it('should have some data', async function () {

    await scope.$apply();

  });

您可能需要移动getNav()调用init有点函数然后针对该init函数进行测试