AngularJS单元测试$ rootScope。$ on

时间:2014-04-27 10:19:19

标签: angularjs unit-testing

我在我的控制器$ rootScope。$ on函数中监听用户登录

        $rootScope.$on('$firebaseSimpleLogin:login',function(e, authUser) {
            User.findByUid(authUser.uid).then(function(user) {

我嘲笑'用户'和'loginService'服务。

    beforeEach(inject(function($controller, $rootScope, $q) {
    scope = $rootScope.$new();
    q = $q;
    headerCtrl = $controller('headerCtrl', {
        $scope: scope,
        loginService: _loginService,
        User: _userService
    });
}));

现在我想测试一下,当$ catch用户登录时,会调用User.findByUid。所以我需要知道如何“模拟”这个$ on方法,这样我就可以检查是否调用了findByUid方法。怎么样?我试过像......

it('should call User.findByUid on $firebaseSimpleLogin:login', function() {
    spyOn(scope, '$on');

            // here I need to probably trigger it somehow...

            // and check or?...
    expect(scope.$on).toHaveBeenCalled();
});

更新 https://gist.github.com/TrkiSF2/39315e7ea980cac6cc9f

侧面问题

当我将我的ctrl代码更改为:

        $rootScope.$on('$firebaseSimpleLogin:login',function(e, authUser) {
            User.findByUid(authUser.uid);
        });

我的模拟用户服务:

            findByUid: function(uid) {
            console.log("dump");
        }

我的测试:

    it('should call User.findByUid on $firebaseSimpleLogin:login', function() {
    spyOn(_userService, 'findByUid');

    var authUser = { uid: 1 };
    scope.$emit('$firebaseSimpleLogin:login', authUser);

    expect(_userService.findByUid).toHaveBeenCalled();
});

它有效...但是为什么控制台中没有“转储”消息,所以我可以确定测试使用的是我的模拟代码,而不是真正的代码。 (假设我确定如果有......那么它将不会执行某些数据库查询。)

上一个问题

如果我的ctrl代码如下所示:

        $rootScope.$on('$firebaseSimpleLogin:login',function(e, authUser) {
            User.findByUid(authUser.uid).then(function(user) {

                User.setCurrentUser(user);

我想检查一下是否也调用了User.setCurrentUser?最好的方法是什么?在一些单独的代码中或以某种方式相同?

可能会回答我的问题吗?

我只是从好奇心中尝试了这将做什么,我为我的模拟用户对象添加了新方法:

        setCurrentUser: function(user) {

        }

我已经解决了我的承诺:

        findByUid: function(uid) {
            defered = q.defer();
                defered.resolve({nick:'Trki'});
            return defered.promise;
        },

然后我更新了我的测试

it('should call User.findByUid on $firebaseSimpleLogin:login', function() {
    spyOn(_userService, 'findByUid').and.callThrough();
    spyOn(_userService, 'setCurrentUser');

    var authUser = { uid: 1 };
    scope.$emit('$firebaseSimpleLogin:login', authUser);
    scope.$root.$digest();

    expect(_userService.findByUid).toHaveBeenCalled();
    expect(_userService.setCurrentUser).toHaveBeenCalled;
});

它说成功!这是好方法吗?

1 个答案:

答案 0 :(得分:1)

窥探用户模拟:

spyOn(_userService, 'findByUid').and.callThrough();

然后使用$broadcast$emit手动调度事件(具体取决于您从哪个范围发送)。如果需要,添加参数:

var authUser = { uid: 1 };
scope.$emit('$firebaseSimpleLogin:login', authUser);

进行验证:

expect(_userService.findByUid).toHaveBeenCalled();

在这种情况下,您需要使用and.callThrough(),因为您在链中添加了then

User.findByUid(authUser.uid).then(function(user) {

如果不通过你的模拟调用不会返回你定义的承诺:

findByUid: function(uid) {
  defered = q.defer();
  return defered.promise;
}

它将尝试在undefined上执行then,因此“'undefined'不是对象”。

侧面问题 - 答案:

如果您添加.and.callThrough();console.log("dump")应该执行。

如果不这样做,将会截获呼叫,保存有关呼叫的信息,但该功能实际上不会执行。

这意味着如果你在监视自己的嘲讽,你几乎总是想要使用callThrough(),因为它会返回模拟数据。

这也意味着你并不总是需要自己的模拟,因为你可以在服务上设置间谍,并且不会执行真正的实现,因为调用将被截获。

然后,您可以使用and.returnValueand.callFake返回或执行模拟逻辑。