通过因果报应测试管理angularjs控制器初始化
Manage angularjs controller init with karma tests
我看到过这样的问题,它们都说"将逻辑提取到服务中并模拟服务"。很简单,除了我有尽可能多的。
因此,当控制器inits i调用$scope.getWidgets()
时,该方法调用widgetService
以获取用户的小部件列表,然后它将使用notifyService
显示toast通知。如果widgetService
拒绝其承诺或者用户没有小部件,则调用notifyService
。这一切都是在控制器启动时完成的。
$scope.getWidgets = function () {
widgetService.getWidgets()
.then(function (widgets) {
if (widgets.length === 0) {
notifyService.notify('no widgets');
}
$scope.widgets = widgets;
})
.catch(function (e) {
notifyService.notify('oh noes');
});
}
//called at bottom of controller
$scope.getWidgets();
现在,我所有的测试都不需要运行任何摘要周期、运行promise等。我试图测试的方法调用服务来保存小部件。如果成功或失败,它将再次调用notifyService
向用户发送通知。我正在测试通知是否使用karma的spyOn
触发,并测试一些标志是否设置正确。没有真正的逻辑,这是在服务中完成的。
$scope.saveWidget = function (widget) {
widgetService.saveWidget(widget)
.then(function () {
notifyService.notify('all dandy');
//set some scope flags, no logic
})
.catch(function (e) {
notifyService.notify('oh noes');
//set some more scope flags, no logic
});
}
所以现在我必须运行摘要循环来触发我的承诺。The Trouble is my mock for widgetService.getWidgets()
return a promise。因此,当我首先运行摘要时,它解析了在init中注册的promise,init调用通知服务,通知服务激活了我的spyon,从而用错误的数据结束了我的测试。
这是我的测试,(请原谅这个大代码块,我试着尽可能地把它去掉)。
describe('tests', function () {
var scope, controlelr, _mockWidgetService, _mockNotifyService;
beforeEach(function () {
//Init the service mocks, angular.noop for methods etc
_mockWidgetService = init();
_mockNotifyService = init();
});
beforeEach(function () {
//Regisetr hooks to pull in my mocked services
angular.mock.module('myModule');
angular.mock.module(function($provide) {
$provide.value('widgetService', _mockWidgetService);
$provide.value('notifyService', _mockNotifyService);
})
});
angular.mock.inject(function ($controller, $rootScope, widgetService, notifyService) {
//create scope and inject services to create controller
scope = $rootScope.$new();
//Trouble is $scope.getWidgets() is called now.
controller = $controller('testController', {
$scope: scope,
widgetService: widgetService,
notifyService: notifyService
});
});
describe('getWidgets', function() {
it('myTest', function () {
//I cannow manipulate mock services moreso if needed just for this test
spyOn(_mockNotifyService, 'notfy');
//Call save widget
scope.saveWidget();
scope.$digest();
expect(_mockNotifyService.notify).toHaveBeenCalledWith(//values);
});
});
});
因此,正如你所看到的,我很挣扎,我可以模拟init代码所需的所有模拟,但我只模拟测试所需的服务。另外,我不喜欢init代码运行每个测试可能会导致错误的想法(它有自己的测试)。
对此类用例的任何建议或解决方案都将不胜感激。
我找到了一个似乎有效的潜在解决方案。我不完全确定它的最佳实践,所以如果有更好的选择,我很感激听到它们。
本质上,我没有在每次测试前用一个已解决的承诺来模拟我的widgetService.getWidgets
,而是用一个从未解决的延迟承诺来模拟它。想法是,对于不需要它的测试,init代码永远不会运行,因为promise永远不会解析。
需要它运行的测试只需覆盖mock,并让widgetService.getWidgets
返回所需内容。
这确实意味着一些小的变化,控制器必须为每个测试手动实例化(在可用的情况下使用beforeEach),而不是在第一个描述的顶部。
- 将值从html传递到AngularJS控制器
- angularjs-控制器在表单提交时未调用
- Angularjs控制器本地错误
- AngularJS:控制器中的函数被模板多次调用
- 将AngularJS控制器拆分为多个文件
- AngularJS控制器范围
- AngularJS控制器不工作,为什么?(简单的控制器示例)
- AngularJS控制器在注入工厂时抛出错误
- 如何使用onclick事件调用AngularJS控制器
- angularjs控制器未启动
- 设置AngularJS控制器属性不能是使用Coffeescript的最后一行
- 如何使AngularJS控制器依赖于通过ajax加载在rootScope上的值
- 通过因果报应测试管理angularjs控制器初始化
- AngularJs 控制器中的实时时钟功能
- Angularjs:控制器的代码组织
- 简单的AngularJS控制器不起作用
- 如何从 angularjs 控制器访问$resource
- 在 html5 视频结束时调用 AngularJS 控制器函数
- AngularJS控制器内部的功能
- AngularJS控制器中基于值的重定向