我见过这样的问题,他们都说要将逻辑提取到服务中并模拟服务'。简单,除了我尽可能多。
因此,当控制器在我调用$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();
现在我所有的测试都不需要运行任何摘要周期,运行运行承诺等。我试图测试的方法调用服务来保存小部件。如果成功或失败,它将再次呼叫notifyService
向用户发送通知。我正在测试使用业力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
});
}
所以现在我必须运行摘要周期来触发我的承诺。麻烦是我模仿widgetService.getWidgets()
返回一个承诺。因此,当我首先运行摘要时,它会解析在我的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);
});
});
});
因为你可以看到即时通讯挣扎,我可以模拟初始化代码所需的所有模拟,但id只是模拟我测试所需的服务。另外,我不喜欢运行每一个测试的init代码的想法可能导致错误的错误(它有自己的测试)。
对此类用例的任何建议或解决方案都将非常感谢。
答案 0 :(得分:0)
我找到了一个似乎有用的潜在解决方案。我不完全确定它的最佳实践,所以如果有更好的选择,请非常感谢听到它们。
基本上不是在每次测试之前使用已解决的承诺来模拟我的widgetService.getWidgets
,而是使用从未解决的延迟承诺来模拟它。对于不需要它的测试的想法永远不会运行,因为承诺永远不会解决。
要求它运行的测试只是覆盖模拟并让widgetService.getWidgets
返回所需的内容。
这确实意味着一些小的变化,控制器必须为每个测试手动实例化(使用beforeEach,如果可用),而不是在第一个描述的顶部。