Nic*_*ner 6 unit-testing mocking angularjs
我有一个服务,将我的其他几个服务作为依赖项.我如何模拟它进行单元测试?
myApp.factory('serviceToTest',
['serviceDependency',
function(serviceDependency) {
return function(args) {
return cond(args) ? serviceDependency() : somethingElse();
};
}
]);
Run Code Online (Sandbox Code Playgroud)
在上面的例子中,我想模拟出来,serviceDependency以便我可以验证它是否被调用.我怎样才能做到这一点?
我可以在测试中执行以下操作:
describe("Services", function() {
describe('serviceToTest', function() {
myApp.factory('serviceDependency', function() {
var timesCalled = 0;
return function() {
return timesCalled++;
}
});
it('should do foo', inject(function(serviceToTest, serviceDependency) {
serviceToTest(["foo", "bar", "baz"]);
expect(serviceDependency()).to.equal(1);
});
});
});
Run Code Online (Sandbox Code Playgroud)
这适用于需要模拟的测试,但它会影响后面所有其他测试的状态,这显然是一个问题.
pko*_*rce 11
如果我理解正确,您希望测试依赖于其他服务的服务并模拟每个测试的依赖项.如果是这样,那么我们说我们car有一个依赖于engine:
var app = angular.module('plunker', [])
.factory('car', function(engine) {
return {
drive : function() {
return 'Driving: ' + engine.speed();
}
}
})
.value('engine', {
speed : function() {
return 'fast';
}
});
Run Code Online (Sandbox Code Playgroud)
然后你想测试汽车并模拟引擎.有两种方法可以这样做:通过定义一个我们可以重新定义引擎的新模块:
describe('Testing a car', function() {
var testEngine;
beforeEach(function(){
testEngine = {};
angular.module('test', ['plunker']).value('engine', testEngine);
module('test');
});
it('should drive slow with a slow engine', inject(function(car) {
testEngine.speed = function() {
return 'slow';
};
expect(car.drive()).toEqual('Driving: slow');
}));
});
Run Code Online (Sandbox Code Playgroud)
这里有一个工作:http ://plnkr.co/edit/ueXIzk? p= preview
更简单的替代方案,转发JavaScript的动态特性:
describe('Testing a car', function() {
var testEngine;
beforeEach(module('plunker'));
beforeEach(inject(function(engine){
testEngine = engine;
}));
it('should drive slow with a slow engine', inject(function(car) {
testEngine.speed = function() {
return 'slow';
};
expect(car.drive()).toEqual('Driving: slow');
}));
});
Run Code Online (Sandbox Code Playgroud)
http://plnkr.co/edit/tlHnsJ?p=preview
另一种选择是使用Jasmine的间谍:
describe('Testing a car', function() {
var testEngine;
beforeEach(module('plunker'));
beforeEach(inject(function(engine){
testEngine = engine;
}));
it('should drive slow with a slow engine', inject(function(car) {
spyOn(testEngine, 'speed').andReturn('slow');
expect(car.drive()).toEqual('Driving: slow');
}));
});
Run Code Online (Sandbox Code Playgroud)
http://plnkr.co/edit/K4jczI?p=preview
我试图将模拟服务注入另一个提供程序时遇到了同样的问题.
Pete Bacon Darwin的这篇文章让我走上正轨:https://groups.google.com/d/msg/angular/TvBknXnjRyQ/xtCDkJyqp6MJ
这是一个示例应用程序:
angular.module('MyApplication', [])
.service('MyServiceDependency', [function(){
// Behaviour here.
}])
.factory('MyFactory', ['MyServiceDependency', function(MyServiceDependency){
// Behaviour here.
}]);
Run Code Online (Sandbox Code Playgroud)
我们想要模拟MyServiceDependency测试行为,MyFactory所以我们编写这样的测试:
describe(function(){
var MyFactory;
beforeEach(function(){
// 1. Include your application module for testing.
angular.mock.module('MyApplication');
// 2. Define a new module.
// 3. Define a provider with the same name as the one you want to mock (in our case we want to mock 'MyServiceDependency'.
angular.module('MyAppMock', [])
.service('MyServiceDependency', function(){
// Define you mock behaviour here.
});
// 4. Include your new mock module - this will override the providers from your original module.
angular.mock.module('MyAppMock');
// 5. Get an instance of the provider you want to test.
inject(function($injector){
// `MyFactory` will receive the mocked version of `MyServiceDependency`.
MyFactory = $injector.get('MyFactory');
});
});
it('MyFactory does something special', function(){
MyFactory(); // Test your provider.
});
});
Run Code Online (Sandbox Code Playgroud)
这是我的开源项目的一个示例:https://github.com/lucassus/mongo_browser/blob/f1faf1b89a9fc33ef4bc4eced386c30bda029efa/spec/javascripts/app/services_spec.js.coffee#L25(对不起coffeescript)。通常,在规范中,您必须创建并包含一个覆盖给定服务的新模块。