【问题标题】:ngMock complains unexpected request when request is expectedngMock 在预期请求时抱怨意外请求
【发布时间】:2015-11-23 17:49:45
【问题描述】:

我的 ng 应用运行良好,但我正在尝试为我的控制器编写一个 ngMock 测试;我基本上遵循 Angular 网站上的示例:https://docs.angularjs.org/api/ngMock/service/$httpBackend

我遇到的问题是即使在预期请求时它也会抱怨意外请求。

PhantomJS 1.9.8 (Windows 8 0.0.0) NotificationsController 应该获取通知列表失败

错误:意外请求:GET 对测试 API/AspNetController/AspNetAction 无效 预期 GET api/AspNetController/AspNetAction

我没有得到的是,在错误行中,为什么在我的服务 url 之前附加了一个“测试”字样? 我认为它应该发送到 'api/AspNetController/AspNetAction' 我在这里做错了什么。我通过谷歌找不到其他人遇到与我相同的问题。

编辑:我注意到,如果我从控制器中删除 sendRequest 部分,并让单元测试在控制台中记录我的请求对象,我会看到以下 json。

{  
   "method":"GET",
   "url":"Not valid for testsapi/AspNetController/AspNetAction",
   "headers":{  
      "Content-Type":"application/json"
   }
}

这里是控制器代码

angular.module('MainModule')
    .controller('NotificationsController', ['$scope', '$location', '$timeout', 'dataService',
        function ($scope, $location, $timeout, dataService) {
            //createRequest returns a request object
            var fetchNotificationsRequest = dataService.createRequest('GET', 'api/AspNetController/AspNetAction', null);
            //sendRequest sends the request object using $http
            var fetchNotificationsPromise = dataService.sendRequest(fetchNotificationsRequest);
            fetchNotificationsPromise.then(function (data) {
                //do something with data.
            }, function (error) {
                alert("Unable to fetch notifications.");
            });
    }]
);

测试代码

describe('NotificationsController', function () {
    beforeEach(module('MainModule'));
    beforeEach(module('DataModule')); //for data service

    var $httpBackend, $scope, $location, $timeout, dataService;

    beforeEach(inject(function ($injector) {

        $httpBackend = $injector.get('$httpBackend');

        $scope = $injector.get('$rootScope');
        $location = $injector.get('$location');
        $timeout = $injector.get('$timeout');
        dataService = $injector.get('dataService');

        var $controller = $injector.get('$controller');

        createController = function () {
            return $controller('NotificationsController', {
                '$scope': $scope,
                '$location': $location,
                '$timeout': $timeout,
                'dataService': dataService,
            });
        };
    }));

    afterEach(function () {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    it('should fetch notification list', function () {
        $httpBackend.expectGET('api/AspNetController/AspNetAction');        //this is where things go wrong
        var controller = createController();

        $httpBackend.flush();
    });

});

数据服务代码

    service.createRequest = function(method, service, data) {
        var req = {
            method: method, //GET or POST
            url: someInjectedConstant.baseUrl + service,
            headers: {
                'Content-Type': 'application/json'
            }
        }

        if (data != null) {
            req.data = data;
        }

        return req;
    }

    service.sendRequest = function (req) {
        return $q(function (resolve, reject) {
            $http(req).then(function successCallback(response) {
                console.info("Incoming response: " + req.url);
                console.info("Status: " + response.status);
                console.info(JSON.stringify(response));

                if (response.status >= 200 && response.status < 300) {
                    resolve(response.data);
                } else {
                    reject(response);
                }
            }, function failCallback(response) {
                console.info("Incoming response: " + req.url);
                console.info("Error Status: " + response.status);
                console.info(JSON.stringify(response));

                reject(response);
            });
        });
    }

回答:

由于 dataService 通过 someInjectedConstant.baseUrl + what_relative_url 从控制器传入创建了最终的 webapi url,在我编写的测试中,我将不得不注入 someInjectedConstant

$httpBackend.expectGET(someInjectedConstant.baseUrl + relativeUrl)

而不仅仅是做一个 $httpBackend.expectGET(relativeUrl)

【问题讨论】:

  • 请您发布您的数据服务和 asp routehandler 代码吗? “测试”很可能会在其中一项中预先设置
  • @br3w5,我已经附加了dataservice的代码,asp路由只是标准的;点击localhost/api/AspNetController/AspNetAction 将显示我需要的 json 数据。在这个阶段,不使用任何身份验证。
  • 我在更改端点时遇到了类似的问题,但这更清楚并且被现有测试捕获......你不应该将GET 改为/api/AspNetController/AspNetAction(注意第一个斜杠) ?
  • @br3w5 好吧,数据服务正在将该斜杠与域 (localhost) 一起附加。有趣的是,该应用程序运行良好,但单元测试却在抱怨。我最初使用的是 jasmine spy,他在解析该端点的模拟数据时没有问题,但由于范围相关的问题,我切换了 ngMock。
  • @br3w5,我刚刚对我的帖子进行了编辑。如果我不发送 $http 请求,并尝试自己记录请求对象。我注意到请求对象中的 url 在创建时是错误的。

标签: javascript angularjs unit-testing angularjs-ngmock


【解决方案1】:

很明显,Not valid for tests 会在您的代码中某处添加到您的 url。它也没有添加硬编码域(见下面的注释)。检查所有代码以及测试管道中可能将其添加到 url 的任何其他部分。

您的代码有几点:

  • 避免在您的代码中硬编码域名(我看到您已在更新的答案中解决了这个问题)
  • 也许someInjectedConstant 可以更明确地命名
  • 你不需要用$q包裹$http,所以service.sendRequest可以是:

    service.sendRequest = function (req) {
        $http(req).then(function (response) { // no need to name the function unless you want to call another function with all success/error code in defined elsewhere
            console.info("Incoming response: " + req.url);
            console.info("Status: " + response.status);
            console.info(JSON.stringify(response));
            return response.data; // angular treats only 2xx codes as success
        }, function(error) {
            console.info("Incoming response: " + req.url);
            console.info("Error Status: " + response.status);
            console.info(JSON.stringify(response));
        });
    }
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 2016-01-17
    • 2013-02-19
    • 1970-01-01
    • 2016-06-12
    • 1970-01-01
    • 2013-11-15
    相关资源
    最近更新 更多