模拟组件功能,用于EmberJS中的组件集成测试

时间:2016-06-03 15:47:26

标签: ember.js mocking integration-testing qunit

让我们假设一个简单的EmberJS组件:

//my-app/components/my-component.js
export default Ember.Component.extend({

  classNames: ['cursor-pointer'],

  doSth(){
      // whatever, state of the component does not change
  },

  clickListener: Ember.on('click', function(){
      this.doSth();
  })
});

现在我想使用集成测试来确定点击组件是否到达(代理)doSth()方法。

moduleForComponent('my-component', 'Integration | Component | stores parser previewer', {
  integration: true
});
test('should call doSth() on click', function (assert) {

   /* Line 3 - the place I tried to set mocked doSth() up */      

   this.render(hbs`{{my-component}}`);
   this.$('.cursor-pointer').click(); // triggers clickListener() correctly
});

问题是我无法用我的模拟替换方法doSth()。 因此,我从未遇到过assert.ok()陈述。

我试图在测试中的第3行插入以下语句:

// idea 1
this.set('doSth', function(){
    assert.ok(true);
  });

// idea 2
this.doSth = function(){
   assert.ok(true);
};

两种方法(想法1,想法2)都不起作用。 this.subject()也不可用,因为它是集成测试,而不是单元测试。

更新 想象doSth()是一个类似于下面所示的openUrlInANewTab()的函数,它不影响组件的状态,也不影响相关的控制器和路由的状态。 示例:

//my-app/components/my-component.js
... 
import openUrlInANewTab from 'my-app/utils/new-tab-opener'; 
... 
export default Ember.Component.extend({
  ...
  doSth(url){ 
     openUrlInANewTab(url); 
  }

,而

// my-app/utils/new-tab-opener.js
export default function openUrlInANewTab(){
      anchor = document.createElement("a");
      ...
      anchor.click();
      ...
}

2 个答案:

答案 0 :(得分:3)

您可以将doSth移至您注入custom-service的服务my-component。然后在测试中你可以通过注入虚假服务来轻松测试。

测试/集成/组件/我的组分-test.js:

test('should call doSth() on click', function(assert) {
  const customStub = Ember.Service.extend({
    doSth() {
      // whatever, state of the component does not change
      console.log('Stubbed doSth fired');
      assert.ok(true, 'Stubbed doSth fired');
    }
  });
  this.register('service:custom-service', customStub);
  this.inject.service('custom-service', { as: 'customService' });
  this.render(hbs`{{my-component}}`);
  this.$('.cursor-pointer').click(); // triggers clickListener() correctly
});

组件/我的-component.js:

import Ember from 'ember';

export default Ember.Component.extend({
  customService: Ember.inject.service('custom-service'),
  classNames: ['cursor-pointer'],

  clickListener: Ember.on('click', function(){
    this.get('customService').doSth();
    console.log('Click listener');
  })
});

答案 1 :(得分:1)

作为Daniel提议的替代方法,您可以考虑在处理组件中的click时使用关闭操作。我的意思是,而不是委托你的一个方法(你做过什么,不能测试)或服务(丹尼尔建议)只是触发一个传递给你的组件的动作。这种方式还为您提供了模拟测试的机会。而且,这种方法导致更具反应性的成分;因为您在运行时将行为从所有者注入到组件中;这使您可以轻松地在不同的上下文(不同的父组件/模板)中重用自定义组件。请参阅twiddle以获取我的意思。