使用$ httpBackend模拟$ http调用更改预期的URL Angular

Ajo*_*uve 21 javascript angularjs

我正在尝试测试正在使用的服务 $http

 var APIClient = function($http) {
     this.send = function(data) {
         $http({
             method: data.method,
             url: data.url,
             headers: data.headers,
             data: data.data
         }).success(function(response, status) {
             data.success(response, status);
         }).error(function(response, status) {
             data.error(response, status);
         });
     }
 }

 angular.module('api.client', []).factory('APIClient', ['$http'
     function($http) {
         var client = new APIClient($http);

         return {
             send: function(data) {
                 return client.send(data);
             },
         }

     }
 ]);
Run Code Online (Sandbox Code Playgroud)

而且测试

  describe('send', function() {

      var apiClient, $httpBackend;

      beforeEach(module('compare'));

      beforeEach(inject(function($injector) {
          $httpBackend = $injector.get('$httpBackend');
          apiClient = $injector.get('APIClient');
      }));

      it('Should check if send() exists', function() {
          expect(apiClient.send).toBeDefined();
      });

      it('Should send GET request', function(done) {
          var url = '/';

          $httpBackend.expect('GET', url).respond({});

          apiClient.send({
              url: url,
              success: function(data, status) {
                  console.log(status);
                  done();
              },
              error: function(data, status) {
                  console.log(status);
                  done();
              }
          });

          $httpBackend.flush();
      });
  });
Run Code Online (Sandbox Code Playgroud)

但我总是有这个错误

PhantomJS 1.9.8 (Mac OS X) send Should send GET request FAILED
        Error: Unexpected request: GET templates/test.html
        Expected GET /
Run Code Online (Sandbox Code Playgroud)

app.js 在这种情况下,预期的url始终是我的最后一个状态

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js

angular.module('compare',
    [
        'ionic',
        'manager.user',
        'api.client',
        'api.user',
        'api.compare',
        'user.controllers',
        'test.controllers'
    ]
)

    .run(function ($ionicPlatform) {
        $ionicPlatform.ready(function () {
            // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
            // for form inputs)
            if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
            }
            if (window.StatusBar) {
                // org.apache.cordova.statusbar required
                StatusBar.styleLightContent();
            }
        });
    })

    .config(function ($stateProvider, $urlRouterProvider) {

        // Ionic uses AngularUI Router which uses the concept of states
        // Learn more here: https://github.com/angular-ui/ui-router
        // Set up the various states which the app can be in.
        // Each state's controller can be found in controllers.js
        $stateProvider

            // setup an abstract state for the tabs directive
            .state('tab', {
                url: "/tab",
                abstract: true,
                templateUrl: "templates/tabs.html"
            })

            // Each tab has its own nav history stack:

            .state('tab.dash', {
                url: '/dash',
                views: {
                    'tab-dash': {
                        templateUrl: 'templates/tab-dash.html',
                        controller: 'DashCtrl'
                    }
                }
            })

            .state('subscription', {
                url: '/subscription',
                templateUrl: 'templates/subscription.html',
                controller: 'SubscriptionCtrl'
            })

            .state('login', {
                url: '/login',
                templateUrl: 'templates/login.html',
                controller: 'LoginCtrl'
            })

            .state('test-compare', {
                url: '/test/compare',
                templateUrl: 'templates/test.html',
                controller: 'TestCompareCtrl'
            })

        // if none of the above states are matched, use this as the fallback
        $urlRouterProvider.otherwise('/login');

    });
Run Code Online (Sandbox Code Playgroud)

我不明白为什么网址正在改变我正在给予/它并测试templates/test.html哪个始终是最后一个状态模板

Tra*_*vis 6

你的主要问题是这一行:

beforeEach(module('compare'));
Run Code Online (Sandbox Code Playgroud)

您在这里加载整个应用程序而不仅仅是apiClient.从本质上讲,您正在进行全面的集成测试,而不是单元测试.

你应该只加载api.client.

beforeEach(module('api.client'));
Run Code Online (Sandbox Code Playgroud)

有用的东西要注意,你也可以这样做:

$httpBackend.whenGET(/templates\/(.*)/).respond('');它基本上忽略了由路由器,控制器或指令加载的所有模板.如果你这样做,它仍然不会被视为单元测试,因为你没有严格测试你的APIClient.

另一个有用的说明

你执行的任何内容.run.config不应该是一个匿名函数,这样你就可以嘲笑它.

这方面的一个例子是:

.config(CompareStateLoader);

CompareStateLoader.$inject = [
    '$stateProvider', 
    '$urlRouterProvider'
];

function CompareStateLoader(
    $stateProvider, 
    $urlRouterProvider
){
    //configure states here 
}
Run Code Online (Sandbox Code Playgroud)

这样做可以让你CompareStateLoader在测试运行器中模拟并加载它.

有关更多信息,请参见约翰爸爸的角风格指南这里.