Javascript 使$httpBackend忽略对服务器的任何请求
我有以下控制器(请注意,在实例化时,我显式调用了Javascript 使$httpBackend忽略对服务器的任何请求,javascript,angularjs,unit-testing,jasmine,httpbackend,Javascript,Angularjs,Unit Testing,Jasmine,Httpbackend,我有以下控制器(请注意,在实例化时,我显式调用了$scope.getNotifications()): 然后我进行了一些单元测试(注意,控制器在每个单元测试之前都会在中实例化): 直到现在一切都很好。所有测试都通过了。但是,当我添加一个不需要任何HTTP调用的新测试(见下文)时,它会失败,因为在afterEach()中,它会验证经验,但在removeNotification()中没有设置期望值。 这是来自karma的错误消息: PhantomJS 1.9.7(Windows 8)notifica
$scope.getNotifications()
):
然后我进行了一些单元测试(注意,控制器在每个单元测试之前都会在中实例化):
直到现在一切都很好。所有测试都通过了。但是,当我添加一个不需要任何HTTP调用的新测试(见下文)时,它会失败,因为在afterEach()
中,它会验证经验,但在removeNotification()中没有设置期望值。
这是来自karma的错误消息:
PhantomJS 1.9.7(Windows 8)notificationCenterController removeNotification应从
电子邮件列表失败
错误:意外请求:获取api/v1/通知
不需要更多请求
it("should remove the given notification from the list", function () {
//arrange
var targetObj = { a: 2 };
scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];
//act
scope.removeNotification(targetObj);
//assert
expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
});
我的大多数测试都有http调用,因此将验证放在afterEach中是有意义的。我想知道在N-1测试中,我还有什么其他选择可以避免复制粘贴每个主体的后面有没有办法告诉$httpBackend
忽略任何调用?您可以在单独的套件中监视$http.get,该套件应该可以工作(下面的伪代码)
由于您在构造函数中发出http请求,并且每次运行测试时都会运行构造函数,因此httpBackend
应该准备好每次响应此请求
因此,在每个
之前的块中,您应该设置:
notificationsRequest = $httpBackend.expectGET("api/v1/notifications").respond(200, {});
在您的测试用例中,您可以通过再次调用respond方法来更改此响应,该方法覆盖响应集,如下所示:
it("should store all notifications from server on the client when success call to server", function () {
//arrange
notificationsRequest.respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
$httpBackend.flush();
//act - done implicitly when controller is instantiated
//assert
expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});
现在,您需要做的就是确保在每次测试之后刷新响应。鉴于此,这可能不方便,但如果您想验证NoOutstandingRequest
,则必须这样做,因为根据构造函数的定义,将有一个未完成的请求。我建议您通过将测试结构化为嵌套套件来实现这一点,对于那些没有测试通知检索的测试,在每个
块之前,在它们自己的中刷新请求。您可以将测试封装在下面的descripe块中
describe("blaController", function () {
var scope, $httpBackend;
beforeEach(module('bla'));
beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$controller('blaCtrl', { $scope: scope });
}));
describe('test http calls', function() {
afterEach(function(){
//assert
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("should get all notifications from server when instantiated", function () {
//arrange
$httpBackend.expectGET("api/v1/notifications").respond(200, {});
$httpBackend.flush();
//act - done implicitly when controller is instantiated
});
it("should store all notifications from server on the client when success call to server", function () {
//arrange
$httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
$httpBackend.flush();
//act - done implicitly when controller is instantiated
//assert
expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});
});
describe('other tests', function(){
it("should remove the given notification from the list", function () {
//arrange
var targetObj = { a: 2 };
scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];
//act
scope.removeNotification(targetObj);
//assert
expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
});
});
});
在我们的项目中,我们将$http调用移动到一个工厂,并在控制器测试中模拟该工厂。这样,您就可以使用$httpBackend测试工厂,并在不使用$httpBackend的情况下测试控制器逻辑代码>在它的最后一行,所以有http调用正在进行。您正在每个
之前的中启动控制器,因此它将在每个测试中重新创建,因此也将在每个测试中执行对$http
的调用。是的,您是对的,我更新了答案以使其更清晰。我知道它们正在生成,但不是针对我想要测试的有问题的方法,因此我在测试中没有设置任何期望值,但在每次测试之后验证仍然会进行。您可以删除$httpBackend,而不是监视$http.get并使用它来执行断言(或者在不同的descripe块中运行非后端测试,并在那里使用spies,这样您就可以两全其美了)。
notificationsRequest = $httpBackend.expectGET("api/v1/notifications").respond(200, {});
it("should store all notifications from server on the client when success call to server", function () {
//arrange
notificationsRequest.respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
$httpBackend.flush();
//act - done implicitly when controller is instantiated
//assert
expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});
describe("blaController", function () {
var scope, $httpBackend;
beforeEach(module('bla'));
beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
scope = $rootScope.$new();
$httpBackend = _$httpBackend_;
$controller('blaCtrl', { $scope: scope });
}));
describe('test http calls', function() {
afterEach(function(){
//assert
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
it("should get all notifications from server when instantiated", function () {
//arrange
$httpBackend.expectGET("api/v1/notifications").respond(200, {});
$httpBackend.flush();
//act - done implicitly when controller is instantiated
});
it("should store all notifications from server on the client when success call to server", function () {
//arrange
$httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
$httpBackend.flush();
//act - done implicitly when controller is instantiated
//assert
expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});
});
describe('other tests', function(){
it("should remove the given notification from the list", function () {
//arrange
var targetObj = { a: 2 };
scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];
//act
scope.removeNotification(targetObj);
//assert
expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
});
});
});