and*_*sit 1 javascript jasmine angularjs
当然,以前有人问过这个问题,但我找不到。我需要模拟一个工厂,但模拟本身需要使用 $q,并且在注入()之后调用模块()时我最终陷入了鸡和蛋的情况。
我看了这个问题,它建议做一个 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);
}
);
}
}
});
Run Code Online (Sandbox Code Playgroud)
茉莉花测试:
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');
});
});
Run Code Online (Sandbox Code Playgroud)
我需要我的 mockMyDependencyFactory 来使用 $q,所以我需要将它包装在inject( function(...,我需要在调用module( function ($provide) {...这当然会给我:
错误:注入器已创建,无法注册模块!
关于我如何解决这个问题的任何建议?
或者,如果您认为我的设计有缺陷(我想我可以实例化 MyDependencyFactory 并在 MyConsumingFactory 实例化期间传递它而不是使用 angular 的 DI?)我全神贯注:)
首先,你所有的调用都module()
应该在 before inject()
,否则你会得到这个错误:Injector already created, can not register a module!
即你应该在将模块注入代码之前注册模块。知道这一点,我们需要MyDependencyFactory
在注入之前模拟,但是$q
如果它只在inject()
. 实际上,这是 angular 测试中的常用技术,将注入的服务分配给测试套件中的全局变量,然后在所有场景中使用它:
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;
});
});
// ....
});
Run Code Online (Sandbox Code Playgroud)
您可以$q
在$provide
块中使用的原因是它不会立即使用,只有在您调用模拟方法或创建模拟对象的实例时才会使用它。到那时,它将被注入并分配给一个全局变量$q
并具有适当的值。
如果您想多次使用不同的值解决您的承诺,您可以做的另一个技巧是创建一个全局变量defer
并不在特定方法中初始化它,而是在某个beforeEach
块中初始化它,然后defer.resolve('something')
在您的场景中使用您想要的值这个特殊的场景。
在这里你可以看到你的代码的一个工作示例,我做了一些额外的修复以使其工作(有评论)。
注意:我说的是“全局”变量,但它实际上并不是 JS 术语中的全局变量,而是特定测试套件中的全局变量。