我们在使用Jasmine测试异步代码时遇到了意外行为。据我们所知,当您使用done
函数时,在执行完成之前不会调用期望值。但是,这没有发生,因为第二个期望失败,因此$ctrl.todos
任务从未发生过
不工作测试
it('initializes the data when $onIinit', (done) => {
const expected = 'some result';
const response = Promise.resolve(expected);
spyOn(myService, 'getAll').and.returnValue(response);
// This method calls myService.getAll
$ctrl.$onInit();
expect(myService.getAll).toHaveBeenCalled();
expect($ctrl.todos).toEqual(false);
response.then(done);
});
输出:预期未定义为等于
另一方面,这是有效的:
it('initializes the data when $onIinit', (done) => {
const expected = 'some result';
const response = Promise.resolve(expected);
spyOn(myService, 'getAll').and.returnValue(response);
// This method calls myService.getAll
$ctrl.$onInit();
expect(myService.getAll).toHaveBeenCalled();
response
.then(() => expect($ctrl.todos).toBe(expected))
.then(done);
});
输出:测试通过
控制器方法:
$ctrl.$onInit = () => {
myService.getAll().then((data) => {
$ctrl.todos = data;
});
};
答案 0 :(得分:2)
我找到了解决方案。我真的不需要另一个then
。具有done
的规范在完成调用之前将无法完成。此外,它应始终放在期望之后。
工作代码:
it('initializes the data when $onIinit', (done) => {
const expected = 'some result';
const response = Promise.resolve(expected);
spyOn(myService, 'getAll').and.returnValue(response);
$ctrl.$onInit();
expect(myService.getAll).toHaveBeenCalled();
response
.then(() => {
expect($ctrl.todos).toBe(expected);
done();
});
});
答案 1 :(得分:0)
您的aproach似乎是正确的,并且可能在done
内调用afterEach
将使其正常工作。
afterEach(function(done) {
done();
}, 1000);
但是,我建议使用$httpBackend,这是适用于使用$http service的单元测试应用程序的虚假HTTP后端实现。我们正在使用angularjs
,对吧?那么,为什么不利用?
使用$httpBackend我们可以发出请求,然后使用模拟数据进行响应,而无需将请求真正发送到真实服务器。这是一个示例性的例子
it('initializes the data when $onIinit', () => {
const mockData = { data: { expected: 'some result' } };
spyOn(myService, 'getAll').and.callThrough();
$httpBackend.expect('POST', '/my-service/url').respond(200, mockData);
// This method calls myService.getAll
$ctrl.$onInit();
//flush pending request
$httpBackend.flush();
expect(myService.getAll).toHaveBeenCalled();
expect($ctrl.todos).toBeDefined();
});
有些解释$httpBackend.expect('POST', '/my-service/url')
,请注意'POST'
需要与method
中您的服务使用的myService.getAll
相匹配,'/my-service/url'
是url
1}}您的服务也在myService.getAll
中使用。
需要致电$httpBackend.flush();
,它会释放所有待处理的请求。
您需要在测试中注入$httpBackend
,这将是一种简单的方法
describe('$httpBackend service in module ngMock', () => {
let $httpBackend;
beforeEach(inject(['$httpBackend', (_$httpBackend) => {
$httpBackend = _$httpBackend;
}]));
it('$httpBackend is defined', () => {
// here we can use $httpBackend
expect($httpBackend).toBeDefined();
});
});
另请注意,$httpBackend
是ngMock模块的一部分。
有关测试angularjs代码here
的更多信息希望有所帮助
答案 2 :(得分:-1)
Promise
来自Angular世界之外 - 您必须等待下一个事件队列中可用的结果 - 脏(几乎是脏的)黑客是使用setTimeout
angular.module('test', [])
.controller('underTest', function($scope, myService) {
$scope.$onInit = function() {
myService.getAll().then(function(data) {
$scope.todos = data
})
}
})
describe('Controller: somethingChanged', function() {
var scope, myService
beforeEach(function() {
module('test')
})
beforeEach(function() {
module(function($provide) {
$provide.value('myService', {
getAll: function() {}
})
})
})
beforeEach(inject(function($controller, _$rootScope_, _myService_) {
myService = _myService_
scope = _$rootScope_.$new()
$controller('underTest', {
$scope: scope
})
}))
it('initializes the data when $onIinit', function(done) {
const expected = 'some result'
const response = Promise.resolve(expected)
spyOn(myService, 'getAll').and.returnValue(response)
scope.$onInit()
expect(myService.getAll).toHaveBeenCalled();
setTimeout(function() {
expect(scope.todos).toEqual(expected)
done()
})
});
});
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine-html.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/2.6.1/boot.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/jasmine/2.6.1/jasmine.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-mocks.js"></script>