我们的Angular项目移至ES6和Reduxjs,现在我正在努力使控制器单元测试正常工作。具体来说,对于类构造函数,我似乎无法正确模拟。根据我的研究,我无法监视ES6类的构造函数,因此我需要模拟其依赖关系,还需要适应ngRedux.connect()促进的词汇“ this”的绑定。
我的测试使其到达构造函数中的connect函数,然后出现错误:“'connect'不是函数”
我认为我在这里可能有几处错误。如果我注释掉构造函数中的连接线,它将进入我的runOnLoad函数,该错误将告诉我fromMyActions不是函数。这是因为redux connect函数将动作绑定到“ this”,因此鉴于这些问题,除非我提供其实现,否则我无法模拟redux。有什么建议吗?我对angular也比较陌生-我最薄弱的领域是单元测试和DI。
这是我的模块和控制器:
export const myControllerModule = angular.module('my-controller-module',[]);
export class MyController {
constructor($ngRedux, $scope) {
'ngInject';
this.ngRedux = $ngRedux;
const unsubscribe = this.ngRedux.connect(this.mapState.bind(this), myActions)(this);
$scope.$on('$destroy', unsubscribe);
this.runOnLoad();
}
mapState(state) {
return {};
}
runOnLoad() {
this.fromMyActions(this.prop);
}
}
myControllerModule
.controller(controllerId, MyController
.directive('myDirective', () => {
return {
restrict: 'E',
controllerAs: 'vm',
controller: controllerId,
templateUrl: htmltemplate
bindToController: true,
scope: {
data: '=',
person: '='
}
};
});
export default myControllerModule.name;
和我的测试:
import {myControllerModule,MyController} from './myController';
import 'angular-mocks/angular-mocks';
describe('test', () => {
let controller, scope;
beforeEach(function() {
let reduxFuncs = {
connect: function(){}
}
angular.mock.module('my-controller-module', function ($provide) {
$provide.constant('$ngRedux',reduxFuncs);
});
angular.mock.inject(function (_$ngRedux_, _$controller_, _$rootScope_) {
scope = _$rootScope_.$new();
redux = _$ngRedux_;
var scopeData = {
data : {"test":"stuff"},
person : {"name":"thatDude"}
} ;
scope.$digest();
controller = _$controller_(MyController, {
$scope: scope,
$ngRedux: redux
}, scopeData);
});
});
});
最佳答案
Redux背后的想法是,大多数控制器没有逻辑,或者逻辑很少。逻辑将主要是动作的创建者,缩减器和选择器。
在您提供的示例中,大多数代码只是接线。
我个人不测试接线,因为它增加的价值很小,而且这类测试通常非常脆弱。
话虽如此,但是如果您要测试控制器,则有两个选择:
使用函数代替控制器类。对于大多数使用类的控制器,不增加任何实际值。而是使用一个函数,然后在另一个纯函数中隔离要测试的逻辑。然后,您甚至不需要模拟等即可测试此功能。
如果仍然要使用类,则需要使用ng-redux存根(类似这样:https://gist.github.com/wbuchwalter/d1448395f0dee9212b70(在TypeScript中))
并像这样使用它:
let myState = {
someProp: 'someValue'
}
let ngReduxStub;
let myController;
beforeEach(angular.mock.inject($injector => {
ngReduxStub = new NgReduxStub();
//how the state should be initially
ngReduxStub.push(myState);
myController = new MyController(ngReduxStub, $injector.get('someOtherService');
}));
注意:我通常不会使用mapDispatchToProps(我通过角度服务公开了动作创建者),因此存根不处理动作,但应该易于添加。