我知道整个互联网上有很多关于这个问题的信息(相信我,我花了整整2天时间搜索所有这些信息)。到目前为止,我发现的任何东西都无法帮助我。
这是我要测试的控制器:
(function () {
"use strict";
angular
.module("productManagement")
.controller("ProductListController", ["productResource", ProductListController]);
function ProductListController(productResource) {
var vm = this;
productResource.query(function(data) {
vm.products = data;
});
vm.showImage = false;
vm.toggleImage = function () {
vm.showImage = !vm.showImage;
}
}
})();
这是一个有效的茉莉花测试:
describe('Controller: ProductListController', function() {
var ProductListController;
beforeEach(function() {
module('productManagement');
inject(function($controller) {
ProductListController = $controller('ProductListController', {});
});
});
it ('showImage should be false', function() {
expect(ProductListController.showImage).toBe(false);
});
});
一切都很好,但现在我想测试vm.products以确保其获得数据。
然而,下面的茉莉花测试失败了(这是我真正想测试的):
describe('Controller: ProductListController', function() {
var ProductListController;
beforeEach(function() {
module('productManagement');
inject(function($controller) {
ProductListController = $controller('ProductListController', {});
});
});
it ('products should be defined', function() {
expect(ProductListController.products).toBeDefined();
});
});
错误是'期望定义未定义'。因此,由于某些原因,产品没有填充数据,但是在运行我的角度应用程序时通常可以正常工作。
所以现在你可能想知道“ productResource 里面发生了什么?” 好吧,你走了:
(function () {
"use strict";
angular
.module("common.services")
.factory("productResource", ["$resource", productResource]);
function productResource($resource) {
return $resource("/api/products/:productId");
}
})();
我的角度应用实际上使用 $ httpBackend 来返回一些虚假的产品信息。因此,我不想在我的茉莉花测试中嘲笑这个,因为那就像嘲笑我的模拟。但是,从技术上讲这是一个单元测试,所以我应该在我的茉莉花测试中嘲笑httpBackend。好吧,我也试过了......
以下是我在测试中尝试模拟httpBackend的代码:
describe('Controller: ProductListController', function() {
var ProductListController, httpBackend, $resource;
beforeEach(function() {
module('productManagement');
inject(function(_$httpBackend_, $controller, _$resource_) {
httpBackend = _$httpBackend_;
ProductListController = $controller('ProductListController', {});
$resource = _$resource_;
});
});
/*afterEach(function() {
//httpBackend.flush();
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});*/
it ('products should be defined', function() {
var productsUrl = '/api/products/:productId';
var products;
httpBackend.whenGET(productsUrl).respond({
'one': 1,
'two': 2
});
httpBackend.expectGET(productsUrl);
var rec = $resource("/api/products/:productId");
rec.query(function(data) {
products = data;
});
//httpBackend.flush();
expect(products.one).toBe(1);
});
});
我必须注释掉httpBackend.flush(),因为错误“没有待处理的请求才能刷新!”。由于其他错误,例如“未满足的请求”,我还必须注释掉afterEach函数。
即使这确实有效,我现在还没有测试我的控制器功能,而是我正在测试$ resource。所以这对我来说似乎不对。
有人可以告诉我我做错了什么吗?我宁愿只做第一种方法,但是在这一点上我会采取任何有效的方法!
答案 0 :(得分:1)
$ httpBackend 是一个ngMock模块服务,您可以在测试代码中使用它来实际模拟 http响应(它有点模仿真实的后端,所以你可以检查您的应用程序如何对潜在的http调用作出反应)。另一方面,在生产代码中,您使用的是 $ resource 服务。在这个地方,它与$ httpBackend无关。
查看此代码
it ('products should be defined', function() {
$httpBackend.expectGET('/api/products').respond({});
$httpBackend.flush();
expect(ProductListController.products).toBeDefined();
});
我们为您的测试添加了两行代码以模仿真实的后端,以便您的productResource将接收数据,就好像它是从后端提供的一样。
答案 1 :(得分:1)
所以我想出来,如果有其他人有这个问题。我现在可以测试在我的茉莉花测试中创建的模拟数据,以及测试我的服务发送的真实数据。
以下是代码演练:
这是我正在测试的角度控制器:
// ProductListController.js
(function () {
"use strict";
angular
.module("productManagement")
.controller("ProductListController", ["productResource", ProductListController]);
function ProductListController(productResource) {
var vm = this;
productResource.query(function(data) {
vm.products = data;
});
vm.showImage = false;
vm.whatever = function() {
return 'returning';
}
vm.toggleImage = function () {
vm.showImage = !vm.showImage;
}
}
})();
这是茉莉花代码,它正确地对控制器进行单元测试,以验证我的控制器中的productResource.query()
方法是否正确地将数据分配给`vm.products'变量。我将在茉莉花中嘲笑这些数据。
describe('Controller: ProductListController', function() {
var ProductListController, $httpBackend;
beforeEach(module('productManagement'));
beforeEach(inject(function($controller, _$httpBackend_) {
ProductListController = $controller('ProductListController', {});
$httpBackend = _$httpBackend_;
}));
it ('products ', function() {
$httpBackend.expectGET('/api/products').respond([{'productId': 13}]);
$httpBackend.flush();
expect(ProductListController.products[0].productId).toBe(13);
});
});
$httpBackend.expectGET
基本上是在等待某些东西 - 在这种情况下我的控制器 - 调用api然后用对象[{'productId': 13}]
进行响应。这样可以适当地嘲弄我的后端,以便我们对控制器功能进行单元测试。
实际进行api调用的productResource代码是在我创建的工厂的幕后,并且正在我的控制器中使用。对于好奇的人来说,这里有 productResource 代码:
(function () {
"use strict";
angular
.module("common.services")
.factory("productResource", ["$resource", productResource]);
function productResource($resource) {
return $resource('/api/products/:productId');
}
})();
现在,回答我原来的问题:在我的茉莉花测试中没有嘲笑http响应,如果我想测试并看看我们的后端发送给我们的控制器,我该怎么做?
嗯,完全免责声明,我没有使用"真实"后端。我实际上在我的实际角度应用程序中使用$ httpBackend来模拟真实的后端。这是因为我遵循了角度教程,这就是教程所做的。所以,我需要在该文件中添加一行代码。这是该文件的snippit和添加的代码行。
(function () {
"use strict";
var app = angular
.module("productResourceMock", ["ngMockE2E"]);
app.run(function ($httpBackend) {
var products = [
{
"productId": 1,
"productName": "Leaf Rake",
"productCode": "GDN-0011",
"releaseDate": "March 19, 2009",
"description": "Leaf rake with 48-inch handle",
"cost": 9.00,
"price": 19.95,
"category": "garden",
"tags": ["leaf", "tool"],
"imageUrl": "http://openclipart.org/image/300px/svg_to_png/26215/Anonymous_Leaf_Rake.png"
},
{
"productId": 5,
"productName": "Hammer",
"productCode": "TBX-0048",
"releaseDate": "May 21, 2013",
"description": "Curved claw steel hammer",
"cost": 1.00,
"price": 8.99,
"category": "toolbox",
"tags": ["tool"],
"imageUrl": "http://openclipart.org/image/300px/svg_to_png/73/rejon_Hammer.png"
},
{
"productId": 2,
"productName": "Garden Cart",
"productCode": "GDN-0023",
"releaseDate": "March 18, 2010",
"description": "15 gallon capacity rolling garden cart",
"cost": 20.00,
"price": 32.99,
"category": "garden",
"tags": ["barrow", "cart", "wheelbarrow"],
"imageUrl": "https://openclipart.org/image/300px/svg_to_png/58471/garden-cart.png"
}
];
var productUrl = "/api/products";
$httpBackend.whenGET(productUrl).respond(products);
// This is the line I added to make my jasmine test work properly
$httpBackend.expectGET(productUrl).respond(products);
现在进行茉莉花测试。它与上面的方法相同,仅使用不同的it
方法。所以这里只是it
方法:
it ('products should really be defined', function() {
$httpBackend.flush();
expect(ProductListController.products[0].productId).toBe(1);
});
我首先冲洗后端,因为我的控制器已经ping了其余的api。然后我检查数据,果然,它包含我的模拟后端发送的内容。完成!
我想如果你想测试你真正的后端数据的正确性,茉莉花测试应该适合你。
很抱歉这个冗长的回答,但我想要彻底,以防有任何noobs(像我一样)谁有同样的问题。