Javascript 余烬组件测试——如何对组件进行单元测试';当它不';不调用外部操作?

Javascript 余烬组件测试——如何对组件进行单元测试';当它不';不调用外部操作?,javascript,testing,ember.js,ember-testing,Javascript,Testing,Ember.js,Ember Testing,我对Ember有些陌生,正在尝试测试寻呼机组件。简化组件如下所示: export default Ember.Component.extend({ index: 0, actions: { next() { this.incrementProperty('index'); } } }); test('next should increment the index by 1', function (assert) {

我对Ember有些陌生,正在尝试测试寻呼机组件。简化组件如下所示:

export default Ember.Component.extend({
    index: 0,
    actions: {
        next() {
            this.incrementProperty('index');
        }
    }
});
test('next should increment the index by 1', function (assert) {
  const component = this.subject();

  assert.equal(component.get('index'), 0, 'Index should be 0');

  component.get('actions').next();
  assert.equal(component.get('index'), 1, 'index should be 1');
});
我试图测试next()操作是否确实按照预期增加了index属性。我编写了一个单元测试,如下所示:

export default Ember.Component.extend({
    index: 0,
    actions: {
        next() {
            this.incrementProperty('index');
        }
    }
});
test('next should increment the index by 1', function (assert) {
  const component = this.subject();

  assert.equal(component.get('index'), 0, 'Index should be 0');

  component.get('actions').next();
  assert.equal(component.get('index'), 1, 'index should be 1');
});
但它失败,错误为“this.incrementProperty不是函数”。调试时,测试中的“this”在next()函数中时,不是组件的上下文——它是一个对象,next()是其唯一属性

我想知道这是否是因为我在测试中调用了nextPlace操作。我知道我可以编写一个集成测试,单击触发此操作的按钮并比较一些UI以确保其更改,但当我试图测试的只是函数本身按预期执行时,这似乎非常复杂。如果它是一个传递给这个组件的动作(闭包动作),我知道我可以在集成测试中设置一个虚拟函数,将其传递给组件,并查看它如何响应。但是这个动作并不调用传递给它的动作


我意识到我正在测试的功能非常基本,但部分原因是为了理解如何在不调用外部(组件)操作的组件中测试操作。

如果您没有表达不编写集成测试的动机,我只建议您编写集成测试。依我看,你的理由是正确的。我有3条建议可以引导您案例的单元测试

首先:不工作的原因是“
component.get('actions')。next
在没有任何上下文的情况下获取对
next
函数的引用。因此
在该调用中无效。要使其有效,只需将组件绑定到它,如下所示:

component.get('actions').next.bind(component)();
next(){
  this.incrementProperty('index');
},
actions:{
  next(){
    this.next();
  }
}
但是我不喜欢这样,因为它是从上下文中提取
next
并再次绑定它。我们正在做
bind
的事情,因为我们知道
next
函数在其代码中引用了
this

因此,我的第二个建议是“如何触发事件”。要触发事件,请查看以下代码:

component.send('next');
依我看,这样更好。我们不需要知道“下一步要做什么”。我们只是在触发一个事件

但这涉及到ember组件的生命周期。我们接受这种情况:有一个名为
actions
的特定哈希,我们可以通过
send
触发它(这完全可以)我们不需要处理
操作
,而可以将
做某事
操作处理
分开。这样,您就可以定义另一个函数来执行所需操作,只需从您的操作处理程序调用它即可。(好的,在这种情况下,我们再次需要知道操作处理程序调用的函数是什么。但这对我来说似乎更清楚。)如下图所示:

component.get('actions').next.bind(component)();
next(){
  this.incrementProperty('index');
},
actions:{
  next(){
    this.next();
  }
}
您可以同时看到所有三个备选方案