我正在用AngularJs和Jasmine进行新的测试。我试图测试登录POST $http服务。我不太确定如何做到这一点,但我有我得到一个错误,我不知道为什么。
This is my login.service.js:
(function () {
'use strict';
angular
.module('app')
.service('loginService', loginService);
/** @ngInject */
function loginService($http) {
var url = 'http://localhost:8080/login';
var service = {
login: login
};
return service;
// ////////// //
function login(user) {
return $http.post(url, user);
}
}
})();
这是我的测试:
describe('login component', function () {
var loginService;
var httpBackend;
var user = {
username: 'ADMIN',
password: 'ADMIN'
};
beforeEach(module('app'));
beforeEach(angular.mock.inject(function (_$httpBackend_, _loginService_) {
loginService = _loginService_;
httpBackend = _$httpBackend_;
}));
it('loginService should be defined', function () {
expect(loginService).toBeDefined();
});
it('loginService.login should be defined', function () {
expect(loginService.login).toBeDefined();
});
describe('We call the Login Service', function () {
beforeEach(function () {
spyOn(loginService, "login").and.callThrough();
});
it('we call the service', function () {
loginService.login(user);
});
it('we look if we called the login service', function () {
expect(loginService.login).toHaveBeenCalled();
});
it('loginService login we send the correct parameters', function () {
expect(loginService.login).toHaveBeenCalledWith('http://localhost:8080/login', 'POST', user);
});
});
});
当它运行时,我得到下一个错误:
PhantomJS 2.1.1 (Linux 0.0.0) login component We call the Login Service we look if we called the login service FAILED
Expected spy login to have been called.
.tmp/app/login/login.spec.js:37:50
loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0) login component We call the Login Service loginService login we send the correct parameters FAILED
Error: <toHaveBeenCalledWith> : Expected a spy, but got Function.
Usage: expect(<spyObj>).toHaveBeenCalledWith(...arguments) in node_modules/jasmine-core/lib/jasmine-core/jasmine.js (line 3340)
.tmp/app/login/login.spec.js:41:54
loaded@http://localhost:9876/context.js:151:17
PhantomJS 2.1.1 (Linux 0.0.0): Executed 6 of 6 (2 FAILED) (0.041 secs / 0.046 secs)
有谁知道我做错了什么吗?谢谢! !
你的测试完全错了。由于您正在测试loginService
,而login
是在该服务上定义的方法,因此您不应该模拟方法login
。
您应该只模拟不属于您正在测试的代码(在本例中为服务)的方法。因此,根据这一点,您应该模拟在$http
服务上执行的post
调用。
可以这样做:
describe('login component', function () {
var loginService;
var $httpBackend;
var user = {
username: 'ADMIN',
password: 'ADMIN'
};
beforeEach(module('app'));
beforeEach(angular.mock.inject(function (_$httpBackend_, _loginService_) {
loginService = _loginService_;
$httpBackend = _$httpBackend_;
$httpBackend.whenPOST('http://localhost:8080/login', user).respond(201, 'SUCCESS');
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
/**
* Ideally, these should be inside a seperate describe block.
*/
// it('loginService should be defined', function () {
// expect(loginService).toBeDefined();
// });
// it('loginService.login should be defined', function () {
// expect(loginService.login).toBeDefined();
// });
//Like this.
describe('Initialization', function(){
it('loginService should be defined', function () {
expect(loginService).toBeDefined();
});
it('loginService.login should be defined', function () {
expect(loginService.login).toBeDefined();
});
});
describe('function: login', function () {
/*
* We should not be spying a method from the service we're trying to test.
* This is anti-pattern. We should be mocking the post call instead.
*/
// beforeEach(function () {
// spyOn(loginService, "login").and.callThrough();
// });
/**
* This test is not doing anything. Each it block should have atleast one expect.
*/
// it('we call the service', function () {
// loginService.login(user);
// });
/**
* This isn't what should be expected here. We should call the method and expect some response.
* The response will be mocked by us using $httpBackend's expectPOST method.
*/
// it('we look if we called the login service', function () {
// expect(loginService.login).toHaveBeenCalled();
// });
// it('loginService login we send the correct parameters', function () {
// expect(loginService.login).toHaveBeenCalledWith('http://localhost:8080/login', 'POST', user);
// });
it('should respond with status 201 and data 'SUCCESS'', function(){
var response = loginService.login(user);
$httpBackend.flush();
response.success(function(res){
expect(res).toEqual("SUCCESS");
});
});
});
});
现在您会发现我已经注释了您的大部分代码。那是因为所遵循的做法都是错误的。
应该遵循的做法是,您应该为代码的不同部分使用多个describe
块。我就是这么做的。请仔细阅读我给出的评论。这将有助于你更好地理解。
希望这对你有帮助!
看看这个本来以为是间谍,结果得到了功能
我认为你的错误是你的间谍所追求的方法实际上是在原型上。您将在错误跟踪中看到Expected a Spy but got a Function
。试着监视原型:
beforeEach(function () {
spyOn(loginService.prototype, "login").and.callThrough();
});
it('we look if we called the login service', function () {
expect(loginService.prototype.login).toHaveBeenCalled();
});
在你的情况下,因为你使用$http
服务,你可以断言ngMock
中提供的expectPOST()
,查看更多angularjs文档,阅读文档中的示例!