问题描述
这肯定已经问过,但我无法找到它。我需要模拟一个工厂,但模拟本身需要使用$ Q和我结束了一个鸡和蛋的情况与问候调用注射后模块()()
Surely this has been asked before but I can't find it. I need to mock a factory, but the mock itself needs to use $q, and I end up in a chicken and egg situation with regards to calling module() after inject().
我看着这个question该建议做一个spyOn,该工程的服务,因为它是一个单身,但我打电话新由我厂返回功能,每次都创建一个新的实例,这样就不会工作...
I looked at this question which advises doing a spyOn, which works for services because it is a singleton, but I am calling new on the function returned by my factory, creating a new instance each time, so that won't work...
var app = angular.module('app', []);
app.factory('MyDependencyFactory', function() {
return function() {
this.doPromise = function () {
var defer = $q.defer();
//obviously more complicated.
defer.resolve();
return defer.promise;
}
}
});
app.factory('MyConsumingFactory', function(MyDependencyFactory) {
return function() {
var dependency = new MyDependencyFactory();
this.result;
this.doSomething = function () {
dependency.doPromise().then(
function (data) {
this.result = data;
},
function (error) {
console.log(error);
}
);
}
}
});
茉莉花测试:
describe('MyConsumingFactory', function() {
var MyConsumingFactory;
beforeEach(function () {
module('app');
inject( function (_MyConsumingFactory_) {
MyConsumingFactory = _MyConsumingFactory_;
});
inject( function ($q) {
mockMyDependencyFactory = function () {
this.doPromise = function (data) {
var defer = $q.defer();
defer.resolve('mock data');
};
};
});
module( function ($provide) {
$provide.factory('MyDependencyFactory', mockMyDependencyFactory);
});
});
it('works correctly', function () {
MyConsumingFactory.doSomething();
$rootScope.$apply();
expect(MyConsumingFactory.result).toEqual('mock data');
});
});
我需要我的mockMyDependencyFactory使用$ Q,所以我需要把它包在注入(功能(... ,然后我需要调用的模块(函数之前做到这一点($提供){... 这当然给我:
I need my mockMyDependencyFactory to use $q, so I need to wrap it in inject( function(..., and I need to do this before the call to module( function ($provide) {... which of course give me:
错误:已创建的喷油器,无法注册模块
我如何避开这个问题有什么建议?
Any suggestions on how I get round this?
或者,如果你觉得我的设计有缺陷的(我想我可以实例化一个MyDependencyFactory并传递MyConsumingFactory化期间,而不是采用了棱角分明的DI吗?)我所有的耳朵:)
Or if you think my design flawed (I suppose I could instantiate a MyDependencyFactory and pass that during instantiation of MyConsumingFactory instead of using angular's DI?) I'm all ears :)
推荐答案
)首先,为模块的所有呼叫(
前应注()
,否则你会得到这个错误:喷油器已经创建,无法注册模块
如您在注射之前应该注册模块!在code。知道了这一点,我们需要注射前嘲弄 MyDependencyFactory
,但我们怎样才能 $ Q
在那里,如果它只是在可注入()
?实际上,它是在角测试的常用技术,以注射服务分配到一个测试套件一个全局变量,然后在所有情况下使用它:
First of all, all your calls to module()
should be before inject()
, otherwise you will get this error: Injector already created, can not register a module!
i.e. you should register modules before you inject them in code. Knowing that, we need to mock MyDependencyFactory
before injecting, but how do we get $q
in there if it is only available in inject()
? Actually, it is a common technique in angular tests, to assign injected service to a global variable in a test suite, and then use it across all scenarios:
describe('some suite', function () {
// "global" variables for injected services
var $rootScope, $q;
beforeEach(function () {
module('app');
module(function($provide) {
$provide.factory('MyDependencyFactory', function () {
return function () {
this.doPromise = function (data) {
// use "globals"
var defer = $q.defer();
defer.resolve('mock data');
return defer.promise;
};
};
});
});
inject(function (_$rootScope_, _$q_) {
// assign to "globals"
$rootScope = _$rootScope;
$q = _$q;
});
});
// ....
});
您可以使用 $ Q
的原因 $提供
块是它没有被立即使用,它会当你调用一个模拟的方法或创建一个嘲笑对象的实例只能使用。到那个时候,它会被注入并分配给全局变量 $ Q
,并有适当的值。
The reason you can use $q
in a $provide
block is that it is not being used immediately, it will be used only when you call a mocked method or create an instance of a mocked object. By that time, it will be injected and assigned to a global variable $q
and have an appropriate value.
还有一招,如果你想用不同的值多次化解你的承诺,你可以做的,就是要创建一个全局变量延迟
并初始化它里面没有具体的方法,但在某些 beforeEach
块,然后执行 defer.resolve('东西')
用值的情况下,你里面想在这个特定的场景。
One more trick you could do if you want to resolve your promise with different values several times, is to create a global variable defer
and initialize it not inside specific method, but in some beforeEach
block, and then do defer.resolve('something')
inside your scenario with a value you want in this particular scenario.
的工作示例,我做了一些额外的修复,使其工作(有评论)。
Here you can see a working example of your code, I've made some extra fixes to make it work (has comments).
请注意:我说的全局变量,但它不是一个特定的测试套件中实际上全球在JS术语,但全球
Note: I am saying "global" variable, but it is not actually global as in JS terminology, but global within a particular test suite.
这篇关于模拟角度工厂使用$ Q在茉莉花的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!