我目前正在阅读一本名为“Mastering Web Application Development with AngularJS”的书,其中一个示例中有一个名为“聚合回调”的测试。
我遇到问题的示例包含 Person 对象:
var Person = function(name, $log) {
this.eat = function(food) {
$log.info(name + ' is eating delicious ' + food);
};
this.beHungry = function(reason) {
$log.warn(name + ' is hungry because: ' + reason);
};
};
名为 Restaurant 的对象:
var Restaurant = function($q, $rootScope) {
var currentOrder;
return {
takeOrder : function(orderedItems) {
currentOrder = {
deferred : $q.defer(),
items : orderedItems
};
return currentOrder.deferred.promise;
},
deliverOrder : function() {
currentOrder.deferred.resolve(currentOrder.items);
$rootScope.$digest();
},
problemWithOrder : function(reason) {
currentOrder.deferred.reject(reason);
$rootScope.$digest();
}
};
};
最后是聚合回调的测试:
it('should allow callbacks aggregation', function() {
var pizzaPid = new Restaurant($q, $rootScope);
var pizzaDelivered = pizzaPid.takeOrder('Margherita');
pizzaDelivered.then(pawel.eat, pawel.beHungry);
pizzaDelivered.then(pete.eat, pete.beHungry);
pizzaPid.deliveryOrder();
expect($log.info.logs).toContain(['Pawel is eating delicious Margherita']);
expect($log.info.logs).toContain(['Pete is eating delicious Margherita']);
});
正如您所看到的,测试没有显示如何将项目添加/注入(inject)到测试中,而且我总体上对 TDD 概念还很陌生。
我最终所做的是将这些全局对象转换为服务和工厂:
angular.module('myApp', [])
.service('Person', function(personName, $log) {
this.eat = function(food) {
$log.info(personName + ' is eating delicious ' + food);
};
this.beHungry = function(reason) {
$log.warn(personName + ' is hungry because: ' + reason);
};
})
.factory('Restaurant', function($q, $rootScope) {
var currentOrder;
return {
takeOrder : function(orderedItems) {
currentOrder = {
deferred : $q.defer(),
items : orderedItems
};
return currentOrder.deferred.promise;
},
deliverOrder : function() {
currentOrder.deferred.resolve(currentOrder.items);
$rootScope.$digest();
},
problemWithOrder : function(reason) {
currentOrder.deferred.reject(reason);
$rootScope.$digest();
}
};
});
但现在我正在努力处理在测试中代表“pawel”和“pete”的服务的多个实例:
describe('Person and Restaurant tests', function() {
var Person;
var Restaurant;
var $q;
var $rootScope;
var $log;
beforeEach(function() {
module('myApp');
module(function($provide) {
$provide.value('personName', 'Pawel');
});
inject(function(_Person_, _Restaurant_, _$q_, _$rootScope_, _$log_) {
Person = _Person_;
Restaurant = _Restaurant_;
$q = _$q_;
$rootScope = _$rootScope_;
$log = _$log_;
});
});
it('should allow callbacks aggregation', function() {
var pizzaDelivered = Restaurant.takeOrder('Margherita');
// here's where the problem is
// with current set up I can only call it as
// pizzaDelivered.then(Person.eat, Person.beHungry);
pizzaDelivered.then(pawel.eat, pawel.beHungry);
pizzaDelivered.then(pete.eat, pete.beHungry);
Restaurant.deliveryOrder();
expect($log.info.logs).toContain(['Pawel is eating delicious Margherita']);
expect($log.info.logs).toContain(['Pete is eating delicious Margherita']);
});
});
正如我所说 - 我是新手,希望得到一些帮助。
最佳答案
测试只允许的原因
pizzaDelivered.then(Person.eat, Person.beHungry)
是因为你创建了一个Person服务。在 Angular 中,服务是单例的。 “人”的概念并不完全符合单例的概念(即在任何给定时间可以有超过 1 个人),但可以在您的应用程序中使用,如下所示:
app = app.module('app', [])
.controller('chicago', function($scope, $log) {
$scope.family = [
new Person('henry', $log),
new Person('me', $log),
new Person('you', $log)
];
});
您应该保留书中定义的人和餐厅。 我相信这就是这本书的意图,因为 在该定义中,有一行独特的代码:
$rootScope.$digest();
http://docs.angularjs.org/guide/concepts 该行调用 Angular 的摘要循环。它基本上贯穿所有 Angular 内容,并使用其上下文中发生的任何更改来更新 DOM 和 View。例如, 如果您的 html 绑定(bind)到 $scope 模型:
<div ng-model='name'> {{ name }} </div>
在对服务器进行几次http调用后,这个模型在js的 Angular 部分发生变化, Angular 会自动更新这个div以具有新名称。 但是,当您的代码存在于 Angular 上下文之外时,必须显式调用 $digest,因为 Angular 不会在其上下文(其 Angular 代码)内意识到已更改的值。您可能唯一一次显式调用 $digest() 是在指令内,但大多数时候它处理第 3 方代码与 Angular 的交互。
这是我前进的建议:
保留人员和餐厅代码。不要将它们转换为 Angular 服务。 在聚合回调测试之前的 beforeEach 函数中,实例化 2 个 Person 对象
beforeEach(function() {
pete = new Person('pete', $log);
pawel = new Person('pawel', $log);
});
我注意到的一件事是,你说这本书的 Person 和 Restaurant 是全局对象,但它们不是。他们有全局函数/构造函数。
这应该会让你的测试通过。
总的来说,我相信这本书教你的是如何使用 Angular 之外的代码。在许多现实应用程序中,您几乎不需要单独使用 Angular js 代码。很多时候您必须使用第三方代码,例如 GoogleMaps、Moment 等。
future 需要记住的事情: 我确实相信 future 的 Angular 版本(2.0),该项目正朝着进一步抽象 $digest 循环并使用 Observe() fn 的方向发展。
关于javascript - Angularjs 和 Jasmine : testing with multiple instances of the same service,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19336949/