我们的Angular项目搬到了ES6和Reduxjs,现在我正努力让控制器单元测试工作。具体来说,当涉及到类构造函数时,我似乎无法正确模拟。从我所研究的内容来看,我无法窥探一个ES6类构造函数,所以我需要模拟它的依赖关系,并且还要适应对词汇的绑定。这个' ngRedux.connect()方便了。
我的测试使它成为构造函数中的connect函数,然后给我错误:"' connect'不是一个功能"
我想我可能有几件事情错了。如果我在构造函数中注释掉连接线,它将进入我的runOnLoad函数,错误将告诉我fromMyActions不是函数。这是因为redux connect函数将动作绑定到“这个”,所以考虑到这些问题,我认为我不能模拟redux,除非我提供它的实现。任何建议?我对角度也相对较新 - 我最薄弱的部分是单元测试和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);
});
});
});
答案 0 :(得分:3)
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(我通过角度服务公开我的动作创建者),因此存根不处理动作,但它应该很容易添加。