3

我在我的项目中使用角度数据表,我想为它编写一个 Jasmine/Karma 单元测试。

这是来自我的控制器的代码:

 $scope.dtOptions = DTOptionsBuilder.fromSource('/api/books/')
                .withBootstrap()
                .withPaginationType('simple_numbers')
                .withDisplayLength(10)
                //.withOption('serverSide', true)
                .withOption('processing', true)
                .withOption('createdRow', createdRow);

            $scope.dtColumns = [
                DTColumnBuilder.newColumn('id').withTitle('ID'),
                DTColumnBuilder.newColumn('name').withTitle('Name')
                DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable()
                    .renderWith(actionsHtml)
            ];

我现在如何为它编写一个单元测试,伪造来自的 JSON 响应/api/books

4

2 回答 2

1
var $scope, $state, DTColumnBuilder, DTOptionsBuilder, createController, $httpBackend;

beforeEach(function () {
  DTColumnBuilder  = {};
  DTOptionsBuilder = {};
  $state           = {};
  $httpBackend     = {};

  module('app', function ($provide) {
    $provide.value('$state', $state);
    $provide.value('$httpBackend', $httpBackend);
    $provide.value('DTColumnBuilder', DTColumnBuilder);
    $provide.value('DTOptionsBuilder', DTOptionsBuilder);
  });

  inject(function ($controller, $injector) {
    $scope = $injector.get('$rootScope').$new();
    $state = $injector.get('$state');
    $httpBackend = $injector.get('$httpBackend');
    DTColumnBuilder  = $injector.get('DTColumnBuilder');
    DTOptionsBuilder = $injector.get('DTOptionsBuilder');

    aliasOfYourController = function () {
      return $controller('originalNameOfController', {
        $scope: scope,
        $state: $state,
        DTOptionsBuilder: DTOptionsBuilder,
        DTColumnBuilder: DTColumnBuilder        
      });
    }

    spyOn($state, 'go');

    $httpBackend.flush();
  });

  afterEach(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
  });

  // Stub out the methods of interest. 
  DTOptionsBuilder.fromSource = angular.noop;
  DTColumnBuilder.bar = function () { return 'bar'; };
});

a 的本质spy是让原始实现做它的事情,但记录对所述函数的所有调用以及各种相关数据。

stub另一方面,Aspy具有扩展的 API,您可以在其中完全修改所述功能的工作方式。返回值、预期参数等

假设我们使用了前面提到的 beforeEach 块,此时DTOptionsBuilder.fromSource将是 a noop。因此,spy使用它并期望该方法已被调用是安全的。

it('should have been called', function () {
  var spy = spyOn(DTOPtionsBuilder, 'fromSource');
  aliasOfYourController();
  expect(spy).toHaveBeenCalled();
});

如果您想操纵所述函数的返回值,我会抓住sinonjs并将其设为stub.

it('became "foo"', function () {
  DTOptionsBuilder.fromSource = sinon.stub().returns('foo');
  aliasOfYourController();
  expect($scope.dtOptions).toEqual('foo');
});

现在,由于您正在使用 Promise,所以它有点复杂,但存根基于 Promise 的函数的基础是:

  • 注入$q您的规范文件。
  • 在已解决的承诺的情况下告诉stub返回。$q.when(/** value **/)
  • 在被拒绝的承诺的情况下告诉stub返回。$q.reject(/** err **/)
  • 运行$timeout.flush()以刷新所有延迟任务。如果您在模拟$httpBackend单元测试中使用的 http 响应并$httpBackend.flush()刷新所有延迟任务。
  • 触发done回调以通知 Jasmine 您已完成等待异步任务(可能不需要)。这取决于测试框架/运行器。

可能看起来像这样:

it('resolves with "foo"', function (done) {
  DTOptionsBuilder.fromSource = sinon.stub().returns($q.when('foo'));
  expect($scope.options).to.eventually.become('foo').and.notify(done); // this is taken from the chai-as-promised library, I'm not sure what the Jasmine equivalent would be (if there is one).
  aliasOfYourController();
  $timeout.flush();
});

而且,如果你想测试,$state.go('toSomeState')那么单元测试用例可以是:

   it('should redirected successfully', function() {
       var stateParams = {
          id: 22,
          name: sample
       }
       functionNameInsideWhichItsBeenCalled(stateParams);
       expect($state.go).toHaveBeenCalledWith('toSomeState', {
           id: stateParams.id,
           name: stateParams.name
       });
   });

现在,很多这只是在这一点上的猜测。如果没有源代码在我旁边运行以供交叉引用,很难设置一个完整工作的测试套件,但我希望这至少会给你一些关于如何使用你的 $httpBackend、spy 和存根的想法。

于 2017-01-16T08:59:49.147 回答
0

要模拟 http 响应,您可以在单元测试中使用 $httpBackend。

如果未发出请求,则希望测试失败时使用 $httpBackend.expect。您也可以定义模拟响应。

$httpBackend.when 当您想要定义模拟响应时使用 $httpBackend.when 如果发出请求但不强制请求。

代码解释...

要测试的控制器代码

self.callme = function() {
    $http.get('/mypath').then(function() {
        console.log("I will be executed when flush is called if the mock API response is 2xx");
    }).catch(function() {
        console.log("I will be executed when flush is called if the mock API response is NOT 2xx");
    });
}

单元测试代码...

$httpBackend.expectGET('/mypath').respond(200, {data:"fred"});
controller.callme();
// The THEN code has not been executed here
$httpBackend.flush();
// The THEN success code is now executed because we responded with 2xx (200)
于 2015-12-23T10:29:46.493 回答