模拟提供者,注入东西

时间:2015-08-21 02:06:30

标签: javascript angularjs unit-testing mocking

我在这里有一个有点复杂的场景,我会尽力解释它,抱歉,如果它感到困惑。

说,我有一个设计好的提供者坐在名为core的模块中,让我们称之为actionProvider,它可以注册操作然后再调用它们。 我这样用它:

 // registering an action in m1 module
 angular.module('m1').config((actionProvider)=> {

     actionProvider.reg('myAction', { $fn: myActionFn });

     myActionFn.$inject = ['$modal'];  

     function myActionFn($modal) {
         $modal.open()    // when action invoked it opens a modal dialog 
     } 
 })


// now somewhere else I invoke that previously registered action 
angular.module('m2').controller('myCtrl', (action)=> {
  action.invoke('myAction');    // and that calls $fn with $modal.open()
})

这完美无缺。现在,假设我必须在无法访问actionProvider源代码的模块中测试actionProvider。意味着我完全需要嘲笑它。 好。我们试着这样做:

 angular.module('core', []).provider('action', function() {
     let self = this;
     self.actions = [];

     self.$get = ()=> { return self }; // essential function that every provider has

     // registering action just pushes it into the array of actions,
     // remember this is a fake provider
     self.reg = (action)=> {
        self.actions.push(action) 
     };

     // yet even though it's a fake it still needs to be able to invoke actions
     self.invoke = (actionName) {
         // so here I need to find specified action in the array and invoke it
     };
})

self.actions中找到正确的操作非常简单。但是如何正确调用$fn?如何告诉注入器找到已注入的所有对象(在myAction的情况下,它将是$modal服务)

1 个答案:

答案 0 :(得分:0)

查找注入myActionFn的内容很简单,只需要检查函数的$inject属性即可。

下一步是简单地调用函数,将需要注入的函数传递给它。

在这种情况下使用Function.prototype.apply无济于事,因为我们需要使用angular的$ injector。使用angular.injector()创建实例也不起作用,因为我们需要使用正确的注入器实例。

诀窍是使用angular.mock.injector来获取当前的注入器实例。

所以我们的invoke函数应如下所示:

 self.invoke = (actionName) {
     // instead of array it's probably better to use an object map for `actions` 
     let action = actions[actionName]; 

     inject(($injector)=> {
         $injector.invoke(action.$fn);
     })
 };