我有一个AngularJS服务,通过$ http这样调用服务器
function DefineCourseService($http) {
var service = {
getCourses: getCourses
};
function getCourses(id) {
return $http({
url: '/api/Course',
method: 'GET'
});
}
}
并且服务器返回:
[{Code:'123',Title:'Test'}]
我想使用Jasmine编写集成测试,从服务器获取响应并检查其值。测试文件如下:
(function() {
'use strict';
define(['angular-mocks', 'defineCourse.service'], function() {
describe("Course service", function() {
var courseService, data, deferredResolution, parentScope;
beforeEach(function() {
module('modabber.services');
});
beforeEach(inject(function($q, $rootScope, DefineCourseService) {
courseService = DefineCourseService;
deferredResolution = $q.defer();
parentScope = $rootScope;
}));
it("get courses", function() {
spyOn(courseService, 'getCourses').and.callThrough();
deferredResolution.resolve();
courseService.getCourses().then(function(result) {
data = result;
});
expect(courseService.getCourses).toHaveBeenCalled();
expect(data).toBeUndefined();
parentScope.$digest();
expect(data).toBeDefined();
done();
});
});
});
})();
最后我的karma.conf.js:
module.exports = function(config) {
config.set({
basePath: '../',
frameworks: ['jasmine', 'requirejs'],
files: [
'karma/test-main.js', {
pattern: 'WebApiControllers/**/*.js',
included: false
}, {
pattern: 'scripts/vendor/*.js',
included: false
}, {
pattern: 'bower_components/ngMidwayTester/src/ngMidwayTester.js',
included: false
}, {
pattern: 'bower_components/**/*.min.js',
included: false
}, {
pattern: 'scripts/*.js',
included: false
}, {
pattern: 'app/services/*.js',
included: false
}, {
pattern: 'app/directives/*.js',
included: false
},
],
exclude: ['scripts/main.js'],
preprocessors: { },
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
}
但它始终失败,因为“数据”未定义,所以问题是什么?
答案 0 :(得分:6)
angular-mock
不会进行真正的ajax调用,因为它可能会使单元测试不准确。为了让Angular调用Web服务并仍然能够保持良好的测试,我建议使用ngMidwayTester。将它与Jasmine的异步支持(done()
功能)结合使用,即可进行测试。
describe('Course service', function() {
var tester;
var courseService;
beforeEach(function() {
tester = ngMidwayTester('modabber.services');
courseService = tester.inject('DefineCourseService');
});
afterEach(function() {
tester.destroy();
tester = null;
});
it('get courses', function(done) {
courseService.getCourses()
.then(function(result) {
expect(result).toBeDefined();
expect(result.Code).toBe('123');
done();
}, function() {
done.fail('Web service call failed!');
});
});
});
答案 1 :(得分:2)
您正在异步回调函数中设置data
,但在外部进行评估。
想象一下你的异步调用需要3秒......这将是它的生命周期:
如果您想像courseService.getCourses()
中那样使用jasmine测试异步调用,则需要使用参数done
通知您的测试。
来自jasmine documentation - Asynchronous support:
在调用中调用done函数之前,此规范不会启动 到之前的每个。并且这个规范在完成之前不会完成 调用。
正如您在文档中看到的那样,基本实现是:
it("takes a long time", function(done) { //done as a parameter
setTimeout(function() {
done(); //done is resolve to finish your test
}, 9000);
});
此外,您需要在收到异步回调后进行评估,因此请在then
回调函数中引入它们。
因此,假设您的服务注入正确,您应该具有以下内容:
it("get courses", function(done) { //Add done as parameter
// spyOn(courseService, 'getCourses').and.callThrough();Now this spyOn makes no sense.
deferredResolution.resolve();
courseService.getCourses().then(function(result) {
data = result;
// expect(courseService.getCourses).toHaveBeenCalled(); Not needed
// expect(data).toBeUndefined(); I assume you are expecting it defined
// parentScope.$digest(); If you are only evaluating result and it's not change by the $scope, you don't need a $digest.
expect(data).toBeDefined();
done();
}, function(){
//If your async call fails and done() is never called,
// your test will fail with its timeout...
//... Or you can force a test error
expect(1).toBe(2);
done();
});
});