所以,我目前正在使用Jasmine + Karma在AngularJS中测试一个函数。我正在尝试创建一个对象,看看它是否已成功添加到数据库中。这个函数调用另一个异步函数,我在测试中似乎无法解释。我知道它永远不会被召唤,因为我没有收到任何回复。没有控制台日志,错误或任何东西。截至目前,我有一个名为StoringService的服务,如下所示:
myApp.service("StoringService", function($http){
// Stores my object
this.store = function(object,success,error){
var request = {
method: "post",
url: "example.com",
headers: {/*...*/},
data: object.toJSON()
};
$http(request).then(
function(response){
console.log("Success! Yay!");
success(response.data.url.script);
},function(response){
console.log("Error! Bummer...");
error(response);
}
);
};
});
我正在测试的主控制器是我的CreationController。这有一个名为Submit的函数,它调用上述服务。这在我运行我的应用程序时有效,但在我运行测试时似乎没有。 submit方法(在CreationController中)看起来像这样:
myApp.controller("CreationController", ["$scope","StoringService",
function($scope,StoringService){
$scope.newObject = new Object();
$scope.successAlert = false; // changed by success() in StoringService
$scope.errorAlert = false; // changed by error() in StoringService
$scope.submit = function(){
StoringService.store($scope.newObject,
function(message){
console.log(message);
},
function(error){
console.log(error);
}
);
}
}]);
最后,当我进入Jasmine + Karma测试时,我注意到我的对象没有被创建,并且经过进一步检查,我的StoringService工作正常,直到实际的$ http请求(示例代码中的第11行)。我不完全确定如何触发这个动作。这是我目前的测试结果。
//creation_test.js
var scope, service;
describe('Creation Test', function(){
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
beforeEach(module('MyApplication'));
beforeEach(inject($rootScope, $controller, $injector){
scope = $rootScope.$new();
service = $injector.get('StoringService');
$controller('CreationController',{
$scope: scope,
StoringService: service
});
}));
// Fails but should pass
it('should create an object',function(done){
scope.newObject.name = "new_object";
scope.newObject.data = "object data";
scope.submit();
setTimeout(function(){
expect(scope.successAlert).toBe(true);
expect(scope.errorAlert).toBe(false);
done();
},5000);
});
afterEach(function(){
jasmine.DEFAULT_TIMEOUT_INTERVL = originalTimeout;
});
);
我不完全确定为什么这不起作用或如何解决它。 successAlert和errorAlert的值永远不会更改,这使我相信永远不会调用$ http请求。我一直在尝试here的可能解决方案,但到目前为止,没有人解决过这个问题。我非常感谢帮助解决这个问题,如果有人找到解决方案,我会非常高兴。
答案 0 :(得分:0)
这是一个工作示例。测试后确保使用args调用服务方法。
expect(loginService.authenticate).toHaveBeenCalledWith({
user: 'david@yahoo.com',
pass: '123'
});
答案 1 :(得分:0)
我已经调整了你的测试。在进行单元测试时,我们不想花时间调用后端,这就是我们需要模拟HTTP调用的原因。当您的store
方法返回一个promise时,我们会在单元测试中模拟这种行为,从而创建一个我们可以控制的延迟保证。稍后您可以resolve
或reject
承诺测试成功和错误。我希望它有所帮助。
describe('Controller: CreationController', function() {
beforeEach(module('MyApplication'));
var storingService;
var deferred;
// Mock services and spy on methods
beforeEach(inject(function($q, StoringService) {
deferred = $q.defer();
storingService = StoringService;
spyOn(storingService, 'store').and.returnValue(deferred.promise);
}));
var CreationController;
var scope;
// Initialize the controller and a mock scope
beforeEach(inject($rootScope, $controller) {
scope = $rootScope.$new();
CreationController = $controller('CreationController', {
$scope: scope,
StoringService: storingService
});
}));
it('should create an object', function() {
scope.submit();
scope.$apply(function() {
deferred.resolve();
});
expect(scope.successAlert).toBe(true);
expect(scope.errorAlert).toBe(false);
});
);