Angularjs 如何在Angular js中使用firebase factory为控制器编写测试?
由于我分别编写了Angularjs 如何在Angular js中使用firebase factory为控制器编写测试?,angularjs,firebase,karma-jasmine,Angularjs,Firebase,Karma Jasmine,由于我分别编写了firebase factory和RecipeController,因此测试中出现了一个错误 TypeError: Cannot read property '$loaded' of undefined. $loaded是firebase中的一种方法 test.js describe('RecipeController', function() { beforeEach(module('leChef')); var $controller; beforeEach(injec
firebase factory
和RecipeController
,因此测试中出现了一个错误
TypeError: Cannot read property '$loaded' of undefined.
$loaded
是firebase
中的一种方法
test.js
describe('RecipeController', function() {
beforeEach(module('leChef'));
var $controller;
beforeEach(inject(function(_$controller_){
$controller = _$controller_;
}));
describe("$scope.calculateAverage", function() {
it("calculates average correctly", function() {
var $scope = {};
var controller = $controller('RecipeController', { $scope: $scope });
$scope.calculateAverage();
expect(average).toBe(sum/(Recipes.reviews.length-1));
});
});
});
firebase-factory.js
app.factory("Recipes", ["$firebaseArray",
function($firebaseArray) {
var ref = new Firebase("https://fiery-inferno-8595.firebaseio.com/recipes/");
return $firebaseArray(ref);
}
]);
recipe-controller.js
app.controller("RecipeController", ["$scope", "toastr", "$location", "$routeParams", "$compile", "Recipes",
function($scope, toastr, $location, $routeParams, $compile, Recipes) {
$scope.recipes.$loaded().then(function(payload) {
$scope.recipe = payload.$getRecord($routeParams.id);
$scope.html = $scope.recipe.instructions;
if (typeof $scope.recipe.reviews === "undefined") {
$scope.recipe.reviews = [{}];
}
$scope.calculateAverage = function(AverageData){
var sum = 0;
if ($scope.recipe.reviews.length > 1) {
for(var i = 1; i < $scope.recipe.reviews.length; i++){
sum += parseInt($scope.recipe.reviews[i].stars, 10);
}
var average = sum/($scope.recipe.reviews.length-1);
var roundedAverage = Math.round(average);
return {
average: roundedAverage,
markedStars: new Array(roundedAverage)
};
} else {
return sum;
}
};
});
]);
app.controller(“RecipeController”、[“$scope”、“toastr”、“$location”、“$routeParams”、“$compile”、“Recipes”,
函数($scope,toastr,$location,$routeParams,$compile,Recipes){
$scope.recipes.$loaded().then(函数(有效负载){
$scope.recipe=payload.$getRecord($routeParams.id);
$scope.html=$scope.recipe.instructions;
if(typeof$scope.recipe.reviews==“未定义”){
$scope.recipe.reviews=[{}];
}
$scope.calculateAverage=函数(平均数据){
var总和=0;
如果($scope.recipe.reviews.length>1){
对于(变量i=1;i<$scope.recipe.reviews.length;i++){
sum+=parseInt($scope.recipe.reviews[i].stars,10);
}
var average=sum/($scope.recipe.reviews.length-1);
var roundedAverage=数学四舍五入(平均值);
返回{
平均值:四舍五入平均值,
markedStars:新阵列(舍入平均值)
};
}否则{
回报金额;
}
};
});
]);
在您的RecipeController
定义中,您立即调用:
$scope.recipes.$loaded().then(function(payload) { ... }
…假设定义了$scope.recipes
,并且其属性为$loaded
——情况并非如此
在您的测试中:
describe("$scope.calculateAverage", function() {
it("calculates average correctly", function() {
var $scope = {};
var controller = $controller('RecipeController', { $scope: $scope });
$scope.calculateAverage();
expect(average).toBe(sum/(Recipes.reviews.length-1));
});
});
…将作用域定义为空对象,然后将其注入控制器
假设您使用Jasmine作为测试框架,您可以这样:
var $scope = {
recipes: {
$loaded: function() { /* this is a mock function */ }
}
};
var deferred = $q.defer();
deferred.resolve({
/* this is the data you expect back from $scope.recipes.$loaded */
});
var promise = deferred.promise;
spyOn($scope.recipes, '$loaded').and.returnValue(promise);
这只是您可以删除该函数并控制测试中获得的数据的许多方法之一。它假定您对和有基本的理解
最佳实践
最好不要将数据附加到$scope
服务。如果您不熟悉,我建议您阅读
TL;DR:控制器只是一个JavaScript“类”,定义函数是它的构造函数。使用var vm=this;
然后将变量附加到实例引用vm
(如在“视图模型”中,或您想调用它的任何地方)
不要依赖已在其他地方定义的
$scope.recipes
,您应该在控制器中明确定义它。如果recipes
是在另一个控制器中定义的,请创建一个两个控制器都可以共享的服务。是否创建一个数组以从中获取一项?您可以使用$firebaseObject
来t一项代替,嗨!Shaun谢谢你,tipp!!我一直在尝试你的建议。但我有另一个错误。$scope.calculateAverage()方法不存在。你能给我更多提示吗?非常感谢!!!在你的测试中,$scope只包含你放入的内容。你真正的问题是,你在应用程序中创建了隐式依赖项,方法是在一个位置将内容附加到$scope,并期望它在另一个位置。测试你的控件变得非常困难如果你能重现问题并发布链接,我会很乐意把它交出来,让它正常工作。