我在每个测试用例之后使用下面的代码重置$broadcast
,但似乎$rootScope.$broadcast.reset();
无法正常运行,因为测试后应该返回1,但它返回6。 / p>
似乎原因是andCallThrough()
,因为在我使用它之前没有andCallThrough()
函数,但是在一些重构之后它给了我TypeError: Cannot read property 'defaultPrevented' of undefined
的错误,所以我不得不使用防止这种错误。
问题是如何在使用broadcast
时重置andCallThrough
,还是有其他更精确的方法?
beforeEach(function() {
spyOn($http, 'post');
spyOn($rootScope, '$broadcast').andCallThrough();
});
afterEach(function() {
$http.post.reset();
$rootScope.$broadcast.reset();
});
it('should make a POST request to API endpoint', function() {
$http.post.andCallThrough();
var response = { id: '123', role: 'employee', email: 'user@email.com', username: 'someUsername' };
$httpBackend.expectPOST(apiUrl + 'login').respond(response);
service.login();
$httpBackend.flush();
$timeout.flush();
expect($rootScope.$broadcast.callCount).toBe(1);
expect($rootScope.$broadcast).toHaveBeenCalledWith(AUTH_EVENTS.loginSuccess, response);
});
答案 0 :(得分:4)
经过长时间的调查,在这种情况下事情是如何运作的,最后通过了测试并且解决方案是当前的:
问题不在于重置广播()或在使用andCallThrough()之后在每个测试用例之后调用reset
方法。
问题是$rootScope.$broadcast.andCallThrough();
由其他事件触发,.callCount()
函数返回6
,这基本上意味着$broadcast
间谍被调用了6次。在我的情况下,我只对AUTH_EVENTS.loginSuccess
事件感兴趣,并确保它只播放一次。
expect($rootScope.$broadcast.callCount).toBe(1);
expect($rootScope.$broadcast).toHaveBeenCalledWith(AUTH_EVENTS.loginSuccess, response);
因此挖掘$rootScope.$broadcast.calls
的方法给了我所有调用的数组,从中可以检索出上述两个调用。因此,解决方案是:
it('should make a POST request to API endpoint', function() {
$http.post.andCallThrough();
var response = { id: '123', role: 'employee', email: 'user@email.com', username: 'someUsername' };
$httpBackend.expectPOST(apiUrl + 'login').respond(response);
service.login();
$httpBackend.flush();
$timeout.flush();
var loginSuccessTriggerCount = _($rootScope.$broadcast.calls)
.chain()
.map(function getFirstArgument(call) {
return call.args[0];
})
.filter(function onlyLoginSuccess(eventName) {
return eventName === AUTH_EVENTS.loginSuccess;
})
.value().length;
expect(loginSuccessTriggerCount).toBe(1);
});
答案 1 :(得分:2)
一种不同的方法。这是一个类似咖啡的伪代码。如果某些表达方式不明确,请在评论中提问。应该说这不是你问题的直接答案。只是一种方法,如何以另一种方式做类似的事情。
使用更纯净的状态进行测试
让我们介绍一个可以处理广播间谍的变量。我使用纯间谍,因为当我们处理方法覆盖或混合时,spyOn
在某些繁琐的情况下可能会有效。
rootScope$broadcastSpy = jasmine.createSpy()
我们需要将原始实现与存根交换,后者将处理间谍及其状态。通常的存根定义说它是一个没有自己逻辑的实体。所以,我们是以纯粹的方式做到这一点,而不是在这里提出任何逻辑。只有一个标记(由间谍代表)。
beforeEach module ($provide) ->
$provide.value '$rootScope',
$broadcast: rootScope$broadcastSpy
return
当然,我们需要在需要重置间谍时谈谈茉莉。
beforeEach ->
rootScope$broadcastSpy.reset()
让我们定义测试范围,我们将准备所有需要的服务,并以声明的方式将它们放到上下文中(即this
)。
instance = (fnAsserts) ->
inject (loginService, $httpBackend, $timeout, apiUrl, AUTH_EVENTS) ->
fnAsserts.call
service: loginService
apiUrl: apiUrl
AUTH_EVENTS: AUTH_EVENTS
'$httpBackend': $httpBackend
'$timeout': $timeout
让我们以黑盒方式编写测试。我们只是设置初始状态,然后开始操作,最后让我们检查标记是否有变化。
it 'should make a POST request to API endpoint', instance ->
# Given
response = { id: '123', role: 'employee', email: 'user@email.com', username: 'someUsername' }
@$httpBackend.expectPOST(@apiUrl + 'login').respond(response)
# When
@service.login()
# Then
@$httpBackend.flush()
@$timeout.flush()
expect(rootScope$broadcastSpy.callCount).toBe(1)
expect(rootScope$broadcastSpy).toHaveBeenCalledWith(@AUTH_EVENTS.loginSuccess, response)
如您所见,我们可以链接实例定义,向它们添加更多信息并以更纯粹的方式编写每个测试,因为我们在单个位置查看状态,范围,模拟和其他所需的内容。我们仅对标记使用闭包,并保证最小化副作用。
答案 2 :(得分:0)
我最后在这里讨论问题的第一部分
重置广播()
这对我有用:
$rootScope.$broadcast.calls.reset()