当使用 sinon 进行单元测试时,我怎么知道我的控制器被调用了?
How do I know my controller was called, when unit testing with sinon?
Angular 中的单元测试还很陌生。我已经阅读了大量关于间谍、存根和模拟的内容,但我在执行基础知识时遇到了很多麻烦:
- 我的控制器是否正确接收传递给构造函数的服务?
- 是否在实例化时调用了
initializePage
?
Controller.spec(很确定需要以下内容)
'use strict';
describe('Controller: MainController', function() {
// load the controller's module
beforeEach(module('myApp'));
var MainController, scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
MainController = $controller('MainController', { $scope: scope });
}));
其余规格:
it('should have called initializePage', function() {
var spyInstance = sinon.spy(MainController, "initializePage");
assert(spyInstance.called, "initializePage() was not called once");
});
});
我一直认为间谍就足够了,但我不确定 MainController
是否被处决了。当前 spyInstance
抛出错误。 我需要在这里存根吗?为什么?
控制器
class MainController {
constructor($scope, $http, $state, Session) {
this.$scope = $scope;
this.$state = $state;
this.Session = Session;
this.initializePage();
}
initializePage() {
//blah blah
}
谢谢。
修订:
main.controller.spec.js
describe('Controller: MainController', function() {
// load the controller's module
beforeEach(module('scriybApp'));
var mainControllerInstance, scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
mainControllerInstance = $controller('MainController', { $scope: scope });
}));
it('should test the controller is in order', function() {
assert.isFunction(mainControllerInstance.$onInit, "$onInit() has not been defined");
sinon.spy(mainControllerInstance, "$onInit");
assert(mainControllerInstance.$onInit.called, "$onInit() called = false");
});
});
控制器测试在 Angular 中有一些缺陷。主要是因为无法监视仅作为 class 实例可用的 class 的构造函数($controller(...)
的结果是)。当$controller(...)
被调用时,没有什么可监视的,构造函数已经被调用,故事结束。
为此,除了 Angular 模块之外,还应使用 ES6/CommonJS 模块来公开控制器 class 并监视原型方法。由于项目中已经使用了ES6,所以是
export class MainController { ... }
和
import { MainController } from '...';
...
scope = $rootScope.$new();
sinon.spy(MainController.prototype, 'initializePage');
mainControllerInstance = $controller('MainController', { $scope: scope });
assert(MainController.prototype.initializePage.called);
assert.strictEqual(mainControllerInstance.$scope, $scope);
...
但更重要的是,initializePage
重新发明了轮子。它的工作已经由 Angular 1.5 及更高版本中的 $onInit
生命周期挂钩处理。它会在指令编译时自动调用,并可以作为 link 前函数的替代。
$onInit
未在控制器实例化时调用,但可以安全地假设它将在指令中,因此无需监视它。更加测试友好,测试变成
class MainController {
constructor($scope, $http, $state, Session) {
this.$scope = $scope;
this.$state = $state;
this.Session = Session;
}
$onInit() {
//blah blah
}
}
和
scope = $rootScope.$new();
mainControllerInstance = $controller('MainController', { $scope: scope });
assert.isFunction(mainControllerInstance.$onInit);
assert.strictEqual(mainControllerInstance.$scope, $scope);
...
Angular 中的单元测试还很陌生。我已经阅读了大量关于间谍、存根和模拟的内容,但我在执行基础知识时遇到了很多麻烦:
- 我的控制器是否正确接收传递给构造函数的服务?
- 是否在实例化时调用了
initializePage
?
Controller.spec(很确定需要以下内容)
'use strict';
describe('Controller: MainController', function() {
// load the controller's module
beforeEach(module('myApp'));
var MainController, scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
MainController = $controller('MainController', { $scope: scope });
}));
其余规格:
it('should have called initializePage', function() {
var spyInstance = sinon.spy(MainController, "initializePage");
assert(spyInstance.called, "initializePage() was not called once");
});
});
我一直认为间谍就足够了,但我不确定 MainController
是否被处决了。当前 spyInstance
抛出错误。 我需要在这里存根吗?为什么?
控制器
class MainController {
constructor($scope, $http, $state, Session) {
this.$scope = $scope;
this.$state = $state;
this.Session = Session;
this.initializePage();
}
initializePage() {
//blah blah
}
谢谢。
修订: main.controller.spec.js
describe('Controller: MainController', function() {
// load the controller's module
beforeEach(module('scriybApp'));
var mainControllerInstance, scope;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller, $rootScope) {
scope = $rootScope.$new();
mainControllerInstance = $controller('MainController', { $scope: scope });
}));
it('should test the controller is in order', function() {
assert.isFunction(mainControllerInstance.$onInit, "$onInit() has not been defined");
sinon.spy(mainControllerInstance, "$onInit");
assert(mainControllerInstance.$onInit.called, "$onInit() called = false");
});
});
控制器测试在 Angular 中有一些缺陷。主要是因为无法监视仅作为 class 实例可用的 class 的构造函数($controller(...)
的结果是)。当$controller(...)
被调用时,没有什么可监视的,构造函数已经被调用,故事结束。
为此,除了 Angular 模块之外,还应使用 ES6/CommonJS 模块来公开控制器 class 并监视原型方法。由于项目中已经使用了ES6,所以是
export class MainController { ... }
和
import { MainController } from '...';
...
scope = $rootScope.$new();
sinon.spy(MainController.prototype, 'initializePage');
mainControllerInstance = $controller('MainController', { $scope: scope });
assert(MainController.prototype.initializePage.called);
assert.strictEqual(mainControllerInstance.$scope, $scope);
...
但更重要的是,initializePage
重新发明了轮子。它的工作已经由 Angular 1.5 及更高版本中的 $onInit
生命周期挂钩处理。它会在指令编译时自动调用,并可以作为 link 前函数的替代。
$onInit
未在控制器实例化时调用,但可以安全地假设它将在指令中,因此无需监视它。更加测试友好,测试变成
class MainController {
constructor($scope, $http, $state, Session) {
this.$scope = $scope;
this.$state = $state;
this.Session = Session;
}
$onInit() {
//blah blah
}
}
和
scope = $rootScope.$new();
mainControllerInstance = $controller('MainController', { $scope: scope });
assert.isFunction(mainControllerInstance.$onInit);
assert.strictEqual(mainControllerInstance.$scope, $scope);
...