EmberJS 2.13 单元测试:将同步代码包装在 运行 循环中?
EmberJS 2.13 unit testing: wrapping synchronous code in a run loop?
这在当前的 Ember 文档中重复了几次,所以我觉得我一定遗漏了什么。让我们来看看 simplest example I found.
为什么对 levelUp 的调用被视为异步以保证将其包装在 运行 循环中?
incrementProperty is synchronous, and as far as I can tell, so is set(但我可能在这里弄错了)
player.js
import DS from 'ember-data';
export default DS.Model.extend({
level: DS.attr('number', { defaultValue: 0 }),
levelName: DS.attr('string', { defaultValue: 'Noob' }),
levelUp() {
let newLevel = this.incrementProperty('level');
if (newLevel === 5) {
this.set('levelName', 'Professional');
}
}
});
玩家-test.js
import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
moduleForModel('player', 'Unit | Model | player', {
// Specify the other units that are required for this test.
needs: []
});
test('should increment level when told to', function(assert) {
// this.subject aliases the createRecord method on the model
const player = this.subject({ level: 4 });
// wrap asynchronous call in run loop
Ember.run(() => player.levelUp());
assert.equal(player.get('level'), 5, 'level gets incremented');
assert.equal(player.get('levelName'), 'Professional', 'new level is called professional');
});
首先,你是完全正确的。指南中的任何地方都没有很好地描述它。
在测试模式下,自动运行 被禁用。您可以从 the guides 中进一步阅读。
但是改变模型中的值会触发一个运行循环。你可以在this twiddle.结果是:
Assertion Failed: You have turned on testing mode, which disabled the
run-loop's autorun. You will need to wrap any code with asynchronous
side-effects in a run
(顺便说一下,set
和 incrementProperty
都会触发这个 运行-循环,正如你猜测的那样。)
那么这里是 运行 循环源:
DS.attr
returns一个computed property with set。
set
函数 triggers an event。
- 最后,a run loop is triggered。
@ykaragol 在他的正确答案中对他的解释是绝对正确的,我没有什么要补充的,为什么你需要将你的代码包装在一个 运行 循环中;因为源代码在那里并且正在调用 emberRun.schedule
,这需要一个 运行 循环。
我想解释的是关于您得到的断言错误的更多信息:"You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run"。这并不直接意味着异步操作(在进行 ajax 调用或触发计时器的意义上)就位。我们大多不知道,但是; Ember.js 确实使用 Ember.run
循环和各种 运行 队列,例如 sync
、actions
、render
、afterRender
等。为了安排我们的代码的效果,以优化我们的应用程序的呈现。即使代码 this.set('levelName', 'Professional');
看起来非常同步; Ember 将其包装在 运行 循环中,以便将计算的 属性 计算或其他更新缓冲在一起,以防止模板的多次渲染(因此降低性能)。
我只希望对 运行 循环、运行 队列或者如何以及为什么在测试中使用 运行 循环有更好的解释,但是没有:(
这在当前的 Ember 文档中重复了几次,所以我觉得我一定遗漏了什么。让我们来看看 simplest example I found.
为什么对 levelUp 的调用被视为异步以保证将其包装在 运行 循环中?
incrementProperty is synchronous, and as far as I can tell, so is set(但我可能在这里弄错了)
player.js
import DS from 'ember-data';
export default DS.Model.extend({
level: DS.attr('number', { defaultValue: 0 }),
levelName: DS.attr('string', { defaultValue: 'Noob' }),
levelUp() {
let newLevel = this.incrementProperty('level');
if (newLevel === 5) {
this.set('levelName', 'Professional');
}
}
});
玩家-test.js
import { moduleForModel, test } from 'ember-qunit';
import Ember from 'ember';
moduleForModel('player', 'Unit | Model | player', {
// Specify the other units that are required for this test.
needs: []
});
test('should increment level when told to', function(assert) {
// this.subject aliases the createRecord method on the model
const player = this.subject({ level: 4 });
// wrap asynchronous call in run loop
Ember.run(() => player.levelUp());
assert.equal(player.get('level'), 5, 'level gets incremented');
assert.equal(player.get('levelName'), 'Professional', 'new level is called professional');
});
首先,你是完全正确的。指南中的任何地方都没有很好地描述它。
在测试模式下,自动运行 被禁用。您可以从 the guides 中进一步阅读。
但是改变模型中的值会触发一个运行循环。你可以在this twiddle.结果是:
Assertion Failed: You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run
(顺便说一下,set
和 incrementProperty
都会触发这个 运行-循环,正如你猜测的那样。)
那么这里是 运行 循环源:
DS.attr
returns一个computed property with set。set
函数 triggers an event。- 最后,a run loop is triggered。
@ykaragol 在他的正确答案中对他的解释是绝对正确的,我没有什么要补充的,为什么你需要将你的代码包装在一个 运行 循环中;因为源代码在那里并且正在调用 emberRun.schedule
,这需要一个 运行 循环。
我想解释的是关于您得到的断言错误的更多信息:"You have turned on testing mode, which disabled the run-loop's autorun. You will need to wrap any code with asynchronous side-effects in a run"。这并不直接意味着异步操作(在进行 ajax 调用或触发计时器的意义上)就位。我们大多不知道,但是; Ember.js 确实使用 Ember.run
循环和各种 运行 队列,例如 sync
、actions
、render
、afterRender
等。为了安排我们的代码的效果,以优化我们的应用程序的呈现。即使代码 this.set('levelName', 'Professional');
看起来非常同步; Ember 将其包装在 运行 循环中,以便将计算的 属性 计算或其他更新缓冲在一起,以防止模板的多次渲染(因此降低性能)。
我只希望对 运行 循环、运行 队列或者如何以及为什么在测试中使用 运行 循环有更好的解释,但是没有:(