肯定以前曾经问过,但我找不到它。我需要模拟一个工厂,但模拟本身需要使用$ q,我最终会遇到关于在inject()之后调用module()的鸡蛋和鸡蛋情况。
我查看了这个question建议做一个spyOn,它适用于服务,因为它是一个单身,但我在函数上调用 new 我的工厂返回,每次都创建一个新的实例,这样就无法工作......
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,所以我需要将它包装在 inject(函数(... )中,我需要在调用模块之前执行此操作(函数) ($ offer){... 当然给了我:
错误:注射器已经创建,无法注册模块!
关于我如何解决这个问题的任何建议?
或者如果你认为我的设计存在缺陷(我想我可以实例化一个MyDependencyFactory并在实例化MyConsumingFactory时传递它而不是使用角度的DI?)我全心全意:)
答案 0 :(得分:4)
首先,您对module()
的所有调用都应该在inject()
之前,否则您将收到此错误:Injector already created, can not register a module!
即您应该在将代码注入模块之前注册模块。知道这一点,我们需要在注入之前模拟MyDependencyFactory
,但如果$q
中只有inject()
,我们如何获得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
您可以在$provide
块中使用$q
的原因是它不会立即使用,只有在调用模拟方法或创建模拟对象的实例时才会使用它。到那时,它将被注入并分配给全局变量defer
并具有适当的值。
如果要多次使用不同的值来解决您的承诺,可以做的另一个技巧是创建一个全局变量beforeEach
并在特定方法内部初始化它,但在某些defer.resolve('something')
块中,然后在您的方案中使用您在此特定方案中所需的值进行With Sheets("Worksheet 2")
.Range("B1").Formula = "=IF(ISERROR(VLOOKUP(A1,'WorkSheet 1'!A:B,2,0))," & """""" & ",VLOOKUP(A1,'Worksheet 1'!A:B,2,0))"
.Range("B1").Copy Range("B2:B" & Range("A" & Rows.Count).End(xlUp).Row)
End With
。
Here you can see a working example of your code,我已经做了一些额外的修复工作(有评论)。
注意:我说的是“全局”变量,但它实际上并不是JS术语中的全局变量,而是特定测试套件中的全局变量。