【问题标题】:How can I simulate a network delay when unit testing an AngularJS controller?单元测试 AngularJS 控制器时如何模拟网络延迟?
【发布时间】:2013-09-25 21:25:11
【问题描述】:

我正在使用模块 ngMock 中的 $httpBackend 服务来模拟 GET 请求。来自AngularJS documentation,这里是一个示例控制器:

// The controller code
function MyController($scope, $http) {
  var authToken;

  $http.get('/auth.py').success(function(data, status, headers) {
    authToken = headers('A-Token');
    $scope.user = data;
  });

  $scope.saveMessage = function(message) {
    var headers = { 'Authorization': authToken };
    $scope.status = 'Saving...';

  $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
    $scope.status = '';
  }).error(function() {
    $scope.status = 'ERROR!';
  });
  };
}

还有,这里是相应的 Jasmine 测试规范:

// testing controller
describe('MyController', function() {
  var $httpBackend, $rootScope, createController;

  beforeEach(inject(function($injector) {
   // Set up the mock http service responses
   $httpBackend = $injector.get('$httpBackend');
   // backend definition common for all tests
   $httpBackend.when('GET', '/auth.py').respond({userId: 'userX'}, {'A-Token': 'xxx'});

   // Get hold of a scope (i.e. the root scope)
   $rootScope = $injector.get('$rootScope');
   // The $controller service is used to create instances of controllers
   var $controller = $injector.get('$controller');

   createController = function() {
     return $controller('MyController', {'$scope' : $rootScope });
   };
 }));


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


 it('should fetch authentication token', function() {
   $httpBackend.expectGET('/auth.py');
   var controller = createController();
   $httpBackend.flush();
 });


 it('should send msg to server', function() {
   var controller = createController();
   $httpBackend.flush();

   // now you don’t care about the authentication, but
   // the controller will still send the request and
   // $httpBackend will respond without you having to
   // specify the expectation and response for this request

   $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
   $rootScope.saveMessage('message content');
   expect($rootScope.status).toBe('Saving...');
   $httpBackend.flush();
   expect($rootScope.status).toBe('');
 });

 it('should send auth header', function() {
   var controller = createController();
   $httpBackend.flush();

   $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
     // check if the header was send, if it wasn't the expectation won't
     // match the request and the test will fail
     return headers['Authorization'] == 'xxx';
   }).respond(201, '');

   $rootScope.saveMessage('whatever');
     $httpBackend.flush();
   });
 });

如上所述,模拟请求在执行测试时会立即响应。我想对模拟 GET 请求设置延迟。这可能吗?我感觉需要$timeout 服务来实现这一目标。

额外问题:这样设置延迟有什么缺点吗?在 AngularJS 单元测试中这样做是否合理?

【问题讨论】:

  • 关于奖金问题:superuser.com/questions/330501/… 我不认为这是您希望在单元测试中拥有的东西
  • @EduardGamonal:我真的不想限制浏览器; angular 的 window.setTimeout 对应项应该足够了。
  • 是的,您可以使用超时,但您应该测试两件事:小带宽和高延迟。您可以使用 iprelay + firefox 油门来做到这一点。我认为单元测试是测试组件的输入/输出,而不是测试应用程序在恶劣的网络条件下的可靠性。
  • 啊,我现在明白你的意思了。

标签: javascript unit-testing angularjs mocking jasmine


【解决方案1】:

为 $httpBackend 创建一个装饰器,像这样:http://endlessindirection.wordpress.com/2013/05/18/angularjs-delay-response-from-httpbackend/

把它放在你的 app.js 中,在每个模拟或直通响应期间有 700 毫秒的延迟:

.config(function($provide) {
    $provide.decorator('$httpBackend', function($delegate) {
        var proxy = function(method, url, data, callback, headers) {
            var interceptor = function() {
                var _this = this,
                    _arguments = arguments;
                setTimeout(function() {
                    callback.apply(_this, _arguments);
                }, 700);
            };
            return $delegate.call(this, method, url, data, interceptor, headers);
        };
        for(var key in $delegate) {
            proxy[key] = $delegate[key];
        }
        return proxy;
    });
})

奖励答案:我相信时间不是你会在单元测试中测试的东西。但是可以肯定的是,您需要测试服务器错误,这就是为什么 mocked http 派上用场的原因。

我在原型设计时使用这样的延迟,这也是一个有效的场景。

【讨论】:

    猜你喜欢
    • 2015-03-15
    • 2014-01-04
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 2012-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多