我有一个用角度编写的服务“dbService”。
devlog.service('dbService', ['$q', function($q) {
this.getLogs = function() {
var deferred = $q.defer();
db.find({}, function(err, docs) {
if(!err) {
deferred.resolve(docs);
} else {
deferred.reject(err);
}
});
return deferred.promise;
}
}
上面的代码从数据库(nedb)中获取数据。它只是 nedb api 的包装器,它返回一个承诺。
单元测试的想法是在不进行任何 xhr 或 db 调用的情况下测试逻辑。
就我而言,我该怎么做?
假设我们违反了上述关注点分离定律,我尝试过以下方式进行测试。
describe("DevLog Services", function() {
var dbService;
var $rootScope;
beforeEach(module('devLog'));
beforeEach(inject(function(_$rootScope_, _dbService_) {
$rootScope = _$rootScope_;
dbService = _dbService_;
}));
it('should work', function(done) {
var promise = dbService.getLogs();
promise.then(function(logs) {
console.log('yipee' + logs);
expect(logs).toBeDefined();
});
$rootScope.$apply();
done();
});
}
上面的代码没有解决这个承诺。
我已经尝试过,添加一个 afterEach 来执行 $rootScope.$apply();
afterEach(function() {
$rootScope.$apply();
}
it('should work', function(done) {
var promise = dbService.getLogs();
var allLogs;
promise.then(function(logs) {
allLogs = logs;
console.log(allLogs);
done();
});
$rootScope.$apply();
expect(allLogs).toBeDefined();
});
在这种情况下,我收到此错误Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
。
至少在这种情况下,promise 正在得到解决。但是在该测试用例完成后它会被解决,这会导致测试用例失败。
任何想法,如何解决这个问题
解决方案:
我找到了解决方案。诀窍是在服务本身中使用 $rootScope.$apply() 。
devlog.service('dbService', ['$q', '$rootScope', function($q, $rootScope) {
this.getLogs = function() {
var deferred = $q.defer();
db.find({}, function(err, docs) {
if(!err) {
deferred.resolve(docs);
} else {
deferred.reject(err);
}
$rootScope.$apply();
});
return deferred.promise;
}
}
并在测试中
it('should work', function(done) {
var promise = dbService.getLogs();
var allLogs;
promise.then(function(logs) {
expect(logs).toBeDefined();
expect(logs.length).toBeGreaterThan(0);
done();
});
});