Unit testing 测试asynchrone函数会给出意外的请求

Unit testing 测试asynchrone函数会给出意外的请求,unit-testing,angularjs,asynchronous,jasmine,Unit Testing,Angularjs,Asynchronous,Jasmine,单元测试: "use strict"; var usersJSON = {}; describe("mainT", function () { var ctrl, scope, httpBackend, locationMock, beforeEach(module("testK")); beforeEach(inject(function ($controller, $rootScope, $httpBackend, $location, $injector) {

单元测试:

"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):

我认为会发生什么:
1.通知后端他将收到什么请求
2.通知后端以空JSON响应该请求
3.创建控制器(执行Search.get)
4.通知后端接收所有请求并回答它们(刷新)

但我总是会遇到以下错误:

Error: Unexpected request: GET : ../solr/users/select?indent=true&wt=json

我没有很好地处理异步搜索功能吗?如何实现这一点?

在单元测试中,您的
lUrl
不应该是相对路径,也就是说,它应该是绝对路径“./solr/users/select?indent=true&wt=json”。因此,如果您的应用程序运行在
”http://localhost/a/b/index.html“
lUrl
应该是
”/a/solr/…“


请注意,您还可以在
$httpBackend.expectGET()
中使用正则表达式,如果您不完全确定绝对路径以后会是什么样子,这可能会有所帮助。

在beforeach中,您应该使用httpBackend.when而不是httpBackend.expect。我认为您不应该在beforeach中使用断言(expect),因此应该将其移动到单独的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({});
        });
    });
这不是真正的“单元”测试,更多的是行为测试

这实际上应该是一些测试:

  • 测试您的服务搜索。确保它调用了正确的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);
            });
        });
    
    });
    

    实际上,您不需要将$httpBackend声明放入beforeach中,因为它只会被使用一次。相反,如果你想把声明留在那里,你可以把清理电话放在一个电话后。这两种方法都有效,但一种方法比另一种更干净。
    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);
            });
        });
    
    });