Ember 组件测试 -- 当不调用外部动作时如何对组件的动作进行单元测试?

Ember component test -- how unit test component's action when it doesn't invoke an external action?

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

export default Ember.Component.extend({
    index: 0,
    actions: {
        next() {
            this.incrementProperty('index');
        }
    }
});

我正在尝试测试 next() 操作是否确实按预期增加了索引 属性。我写了一个这样的单元测试:

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 is not a function"。调试,测试中的 "this" 在 next() 函数内部时,不是组件的上下文——它是一个对象, next() 作为它唯一的 属性.

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

我意识到我正在测试的功能确实很基础,但这在一定程度上是为了了解如何在不调用外部(对组件)操作的组件中测试操作。

如果你没有表达不写集成测试的动机,我只建议你写一个集成测试。 IMO,你的理由是有效的。我有 3 条针对您的案例启动单元测试的建议。

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

component.get('actions').next.bind(component)();

但我不喜欢这个,因为它从上下文中提取 next 并再次绑定它。我们正在做这个 bind 事情,因为我们知道 next 函数在其代码中引用了 this

所以我的第二个建议是"triggering the event some how"。要触发它,请查看以下代码:

component.send('next');

海事组织,这更好。我们不需要知道 "what next is doing"。我们只是触发一个事件。

但这是处理 ember 组件的生命周期。我们接受这种情况:有一个名为 actions 的特定哈希,我们可以通过 send 触发它。 (这完全没问题。)我们可以将 doing somethingaction handling 分开,而不是处理 actions。所以你可以定义另一个函数来做你需要的,然后简单地从你的动作处理程序中调用它。 (好吧,在这种情况下我们又需要知道动作处理程序调用了什么函数。但这对我来说似乎更清楚。)如下所示:

next(){
  this.incrementProperty('index');
},
actions:{
  next(){
    this.next();
  }
}

您可以在 this twiddle 查看所有三个备选方案。