Angular1.5+ 的component语法很赞, 但是对它们做单元测试时难住了我.
指令的测试向来比较繁琐, 需要$compile拿到element, 在通过element得到controller.
beforeEach(angular.mock.inject($injector => {
$compile = $injector.get('$compile');
$rootScope = $injector.get('$rootScope');
scope = $rootScope.$new();
element = $compile(`
<input name="tel" ng-model="tel" type="tel"/>
`)(scope);
$rootScope.$apply();
controller = element.controller('ngModel');
}));
虽然component是directive的语法糖, 但是它的测试却有点不太一样, 在component doc 中提到了一个$componentController服务, 它包含在ngMock中, 这个服务的优点在于你可以不用创建DOM元素就能测试controller.
Component测试实例
假设有如下Component
export const FormRenderComponent = {
template,
controller,
bindings: {
data: '<',
name: '@',
onSave: '&'
}
};
---Magic Is Here---
为了拿到该组件的控制器, 代码非常简单.
let $componentController, controller;
let bindings = {
data: [],
name: 'form name',
onSave: angular.noop
};
beforeEach(angular.mock.inject($injector => {
$componentController = $injector.get('$componentController');
controller = $componentController('formRender', null, bindings);
}));
$componentController的第一个参数就是需要测试的组件名, 通过.component注册在模块上的, 第二个参数是locals可以用来提供$scope, $attr, $element, 第三个参数是bindings的值. 如需更详细的描述请查阅官方文档. 如果你locals几个对象全用上了, 变得很复杂, 建议还是用$compile的方式拿controller.
.component('formRender', FormRenderComponent)
测试代码就就随意发挥了, 举个简单的例子, 测试bindings的数据是否赋值成功.
it('bindings should work', () => {
expect(controller.data).toEqual(bindings.data);
expect(controller.name).toEqual(bindings.name);
});
不要忘了$onInit()
如果你的组件实现了$onInit生命周期函数, 进行测试的时候必须确保手动调用, $ 否则不会触发.
it('$onInit() should init data and events', () => {
spyOn(controller, 'initData');
spyOn(controller, 'initEvents');
controller.$onInit();
expect(controller.initData).toHaveBeenCalled();
expect(controller.initEvents).toHaveBeenCalled();
});
为了代码的质量和可读性, 单元测试是必须的, 如果你还没有养成写单元测试的习惯, 那就从现在开始吧.