Тестирование асинхронной функции дает неожиданный запрос
Unittest:
"use strict";
var usersJSON = {};
describe("mainT", function () {
var ctrl, scope, httpBackend, locationMock,
beforeEach(module("testK"));
beforeEach(inject(function ($controller, $rootScope, $httpBackend, $location, $injector) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
locationMock = $location;
var lUrl = "../solr/users/select?indent=true&wt=json",
lRequestHandler = httpBackend.expect("GET", lUrl);
lRequestHandler.respond(200, usersJSON);
ctrl = $controller("mainT.controller.users", { $scope: scope, $location: locationMock});
httpBackend.flush();
expect(scope.users).toBeDefined();
}));
afterEach(function () {
httpBackend.verifyNoOutstandingRequest();
httpBackend.verifyNoOutstandingExpectation();
});
describe("method test", function () {
it('should test', function () {
expect(true).toBeFalsy();
});
});
});
Контроллер, который я тестирую (работает): Асинхронная функция в init, которая доставляет мне проблемы (использует../solr/users/select?indent=true&wt=json):
$scope.search = function () {
var lStart = 0,
lLimit = privates.page * privates.limit;
Search.get({
collection: "users",
start: lStart,
rows: lLimit)
}, function(records){
$scope.users= records.response.docs;
});
};
Что я думаю происходит:
1. сообщите бэкэнду, какой запрос он получит
2. сообщить бэкэнд для ответа на этот запрос с пустым JSON
3. создать контроллер (Search.get get выполняется)
4. сообщите бэкэнду, чтобы получать все запросы и отвечать на них (сбрасывать)
Все же я всегда получаю следующую ошибку:
Error: Unexpected request: GET : ../solr/users/select?indent=true&wt=json
Я плохо справляюсь с функцией асинхронного поиска? как это должно быть сделано?
3 ответа
В BeforeEach вы должны использовать httpBackend.when вместо httpBackend.expect. Я не думаю, что у вас должно быть утверждение (ожидаемое) в вашем BeforeEach, поэтому его следует перенести в отдельный блок it(). Я также не вижу, где определяется lRequestHandler. Статус 200 отправляется по умолчанию, поэтому он не нужен. Ваша строка httpBackend должна выглядеть так:
httpBackend.when("GET", "/solr/users/select?indent=true&wt=json").respond({});
Ваш тест должен быть:
describe("method test", function () {
it('scope.user should be defined: ', function () {
expect(scope.user).toEqual({});
});
});
Это на самом деле не "модульный" тест, это скорее поведенческий тест.
Это должно быть несколько тестов:
- Проверьте свой сервис Search.get, чтобы убедиться, что он вызывает правильный URL и возвращает результат.
- Проверьте ваш метод контроллера, чтобы убедиться, что он вызывает Search.get
- Проверьте свой метод контроллера, чтобы убедиться, что он помещает результат в правильное место.
Код, который вы разместили, немного неполон, но вот два модульных теста, которые должны охватить вас:
Это то, о чем я подробно писал в блоге, а записи более подробно:
Вот пример того, о чем я говорю:
describe('Search', function () {
var Search,
$httpBackend;
beforeEach(function () {
module('myModule');
inject(function (_Search_, _$httpBackend_) {
Search = _Search_;
$httpBackend = _$httpBackend_;
});
});
describe('get()', function () {
var mockResult;
it('should call the proper url and return a promise with the data.', function () {
mockResult = { foo: 'bar' };
$httpBackend.expectGET('http://sample.com/url/here').respond(mockResult);
var resultOut,
handler = jasmine.createSpy('result handler');
Search.get({ arg1: 'wee' }).then(handler);
$httpBackend.flush();
expect(handler).toHaveBeenCalledWith(mockResult);
$httpBackend.verifyNoOutstandingRequest();
$httpBackend.verifyNoOutstandingExpectation();
});
});
});
describe('myCtrl', function () {
var myCtrl,
$scope,
Search;
beforeEach(function () {
module('myModule');
inject(function ($rootScope, $controller, _Search_) {
$scope = $rootScope.$new();
Search = _Search;
myCtrl = $controller('MyCtrl', {
$scope: scope
});
});
});
describe('$scope.foo()', function () {
var mockResult = { foo: 'bar' };
beforeEach(function () {
//set up a spy.
spyOn(Search, 'get').andReturn({
then: function (fn) {
// this is going to execute your handler and do whatever
// you've programmed it to do.. like $scope.results = data; or
// something.
fn(mockResult);
}
});
$scope.foo();
});
it('should call Search.get().', function () {
expect(Search.get).toHaveBeenCalled();
});
it('should set $scope.results with the results returned from Search.get', function () {
expect(Search.results).toBe(mockResult);
});
});
});
Ваш lUrl
в модульном тесте не должен быть относительный путь, т. е. вместо "../solr/users/select?indent=true&wt=json" он должен быть абсолютным "/solr/users/select?indent=true&wt= JSON". Так что если ваше приложение работает на "http://localhost/a/b/index.html"
, lUrl
должно быть "/a/solr/..."
,
Обратите внимание, что вы также можете использовать регулярные выражения в $httpBackend.expectGET()
Это может быть полезно здесь, если вы не совсем уверены, как будет выглядеть абсолютный путь в дальнейшем.