【问题标题】:How to override mocked response of $httpBackend in Angular?如何在 Angular 中覆盖 $httpBackend 的模拟响应?
【发布时间】:2013-07-25 09:37:58
【问题描述】:

是否可以在模拟 $httpBackend 中覆盖或重新定义模拟响应?

我有这样的测试:

beforeEach(inject(function ($rootScope, $controller, _$httpBackend_) {
  $httpBackend = _$httpBackend_;

  //Fake Backend
  $httpBackend.when('GET', '/myUrl').respond({}); //Empty data from server
  ...some more fake url responses...     
 }

这在大多数情况下都很好,但我很少有测试需要为同一个 URL 返回不同的东西。但是似乎一旦定义了 when().respond() 之后,我就无法在这样的代码中更改它:

单个特定测试中的不同反应:

it('should work', inject(function($controller){
  $httpBackend.when('GET', '/myUrl').respond({'some':'very different value with long text'})

  //Create controller

  //Call the url

  //expect that {'some':'very different value with long text'} is returned
  //but instead I get the response defined in beforeEach
}));

我该怎么做? 我的代码现在无法测试:(

【问题讨论】:

  • 我已经通过将单元测试分成 2 个文件来“解决”它。每个文件都有自己的 $httpBackend.when().respond() 定义。这是一个丑陋的解决方案,但到目前为止我没有找到更好的解决方案。
  • 我在使用 http 的 ng-describe 模拟时遇到了同样的问题,例如 github.com/kensho/ng-describe#mock-httpget - 它似乎在它使用 $httpBackend.when(...) 的引擎盖下,当我后来想要 deps.$httpBackend.expect("POST", "foobar") 并断言deps.$httpBackend.verifyNoOutstandingExpectation(); 我收到一个错误 Error: Unsatisfied requests: POST foobar。似乎使用 ng-describe $http 模拟使得以后无法使用 httpBackend.expect()

标签: unit-testing angularjs mocking


【解决方案1】:

另一种选择是:

你可以使用 $httpBackend.expect().respond() 而不是 $httpBackend.when().respond()

使用expect(),您可以推送相同的网址两次,并按照您推送它们的相同顺序获得不同的响应。

【讨论】:

  • 其实when()应该是用于端到端测试而不是单元测试。
【解决方案2】:

在您的测试中使用 .expect() 而不是 .when()

var myUrlResult = {};

beforeEach(function() {
  $httpBackend.when('GET', '/myUrl')
      .respond([200, myUrlResult, {}]);
});


it("overrides the GET" function() {
  $httpBackend.expect("GET", '/myUrl')
      .respond([something else]);
  // Your test code here.
});

【讨论】:

  • [something else] 中有什么内容?是否需要测试中的.respond
【解决方案3】:

文档似乎建议采用这种风格:

var myGet;
beforeEach(inject(function ($rootScope, $controller, _$httpBackend_) {
    $httpBackend = $_httpBackend_;
    myGet = $httpBackend.whenGET('/myUrl');
    myGet.respond({});
});

...

it('should work', function() {
    myGet.respond({foo: 'bar'});
    $httpBackend.flush();
    //now your response to '/myUrl' is {foo: 'bar'}
});

【讨论】:

  • Reference: "when() 返回一个带有响应方法的对象,该方法控制如何处理匹配的请求。您可以保存此对象以供以后使用并再次调用响应以更改匹配的方式请求已处理。”
  • 如果我在某个“基类”文件中有引用 (myGet),该文件与所有测试共享 beforEach,我需要在其他特定测试/文件中引用它怎么办?跨度>
【解决方案4】:

在响应中使用函数,例如:

var myUrlResult = {};

beforeEach(function() {
  $httpBackend.when('GET', '/myUrl').respond(function() {
    return [200, myUrlResult, {}];
  });
});

// Your test code here.

describe('another test', function() {
  beforeEach(function() {
    myUrlResult = {'some':'very different value'};
  });

  // A different test here.

});

【讨论】:

    【解决方案5】:

    您可以在执行测试的同一函数中重置“何时”响应。

    it('should work', inject(function($controller){
        $httpBackend.when('GET', '/myUrl').respond({'some':'value'})
        // create the controller
        // call the url
        $httpBackend.flush();
        expect(data.some).toEqual('value');
    });
    it('should also work', inject(function($controller){
        $httpBackend.when('GET', '/myUrl').respond({'some':'very different value'})
        // create the controller
        // call the url
        $httpBackend.flush();
        expect(data.some).toEqual('very different value');
    });
    

    请参阅此 plunker 中的示例:http://plnkr.co/edit/7oFQvQLIQFGAG1AEU1MU?p=preview

    【讨论】:

    • 你 plunkr 没有在 beforeEach 方法中设置响应,所以你实际上并没有覆盖任何值。你添加一个 beforeEach 并且一切都开始失败:plnkr.co/edit/A44vSX?p=preview
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 2016-03-13
    • 2020-11-05
    • 2014-12-10
    相关资源
    最近更新 更多