问题 如何使用qunit在Ember单元测试中依赖商店作为服务?


根据 博客文章 对于 ember-data 版 1.0.0-beta.16 商店现在可以用作服务:

TweetComposerComponent = Ember.Component.extend({
  store: Ember.inject.service()      
});

但是,我无法弄清楚该怎么做 qunit 对这样的组件进行单元测试。我尝试过以下方法:

moduleForComponent('tweet-composer', {
  needs: ['service:store']
});

和:

moduleForComponent('tweet-composer', {
  needs: ['store:main']
});

当我做前者时,我得到一个错误 Attempting to register an unknown factory: 'service:store' 如果我做后者那么 store 是 undefined

思考?

(我正在写一篇文章 ember-cli 风格的应用程序)

更新:

似乎有一个 公开问题 为此在ember-test-helpers repo中。

当我等待这个修复时,我制作了一个可以作为一种间隙测量的辅助工具(coffeescript):

`import TestModuleForComponent from 'ember-test-helpers/test-module-for-component'`
`import { createModule } from 'ember-qunit/qunit-module'`

# This assumes the last argument, the callbacks, is present, although it
# does support the description being an optional argument.
moduleForStoreComponent = ->
  args = Array.prototype.slice.call arguments
  callbacks = args[args.length-1]
  # Wrap the original beforeEach callback in a modified version that
  # also sets up the store for the test container.
  originalSetup = callbacks.beforeEach
  callbacks.beforeEach = ->
    DS._setupContainer(@container)
    originalSetup.call(@) if originalSetup
  callbacks.store = ->
    @container.lookup('store:main')
  args.unshift TestModuleForComponent
  createModule.apply @, args

`export default moduleForStoreComponent`

6982
2018-04-20 19:40


起源



答案:


单元测试是除了您正在测试的代码/组件/单元之外,一切都能正常工作的地方。

所以,即使是 store 应假设工作正常(0错误/错误)。

这样的东西应该在你的测试中起作用:

moduleForComponent('tweet-composer', {
    beforeEach: function() {
        this.subject({
            store: {/*empty object*/}
        });
    }
});

如果部分测试依赖于从商店检索的数据,您可以执行以下操作:

this.subject({
    store: {
        find: function() {
          var mockedModel = Ember.Object.create({/*empty*/});
          return mockedModel;
        }
    }
});

这是为了保持“单元测试”的状态,如果你开始包含并注册你的应用程序中的其他对象,你将实际编写集成测试。

注意:

通常,直接在组件中查找模型是一种方法   反模式,你应该更喜欢传递你需要的任何模型   包含该组件的模板。

http://discuss.emberjs.com/t/should-ember-components-load-data/4218/2?u=givanse


12
2018-04-20 23:54



验收测试极其缓慢。如果我正在测试应用程序的许多方面,我更喜欢只使用它们。如果我正在测试两个部分,那么仅仅实例化这两个部分并将它们一起测试就更有意义了,但是与应用程序的其余部分隔离开来。 - Kevin Bullaughey
我知道你提到的那个帖子,我很欣赏这个建议,但是我在营地里觉得有一些有限的,适当的用途可以在某些组件中启用商店访问。特别是,当组件中表示的状态不是从URL派生时,而是组件的内在和隔离方面时,在组件中隔离此状态并且不污染具有该组件的所有路径是有意义的。实例化模型并将其更新为组件内部状态所需的逻辑更改。 - Kevin Bullaughey
同意,你有一个很好的观点。即使这样,在这种类型的测试(您的组件)中,您正在测试的是组件的逻辑而不是存储。因此,数据的来源并不重要。测试需要做的是验证不同的数据块是否触发了正确的事件并导致预期的输出。 - givanse
是的,虽然我正在使用 http-mocks 对于我的模型灯具,能够与真实的模拟数据一起测试组件是很好的,这些数据位于中心位置并且不会分布在我的所有数百个测试文件中。我意识到这意味着它本身并不是一个“单元测试”,但它是我认为最有用的测试粒度。我很感激你的回答,并且会对它进行投票,因为我学会了如何使用存根 subject,但我仍然坚持另一个让我做我想做的答案。 - Kevin Bullaughey


答案:


单元测试是除了您正在测试的代码/组件/单元之外,一切都能正常工作的地方。

所以,即使是 store 应假设工作正常(0错误/错误)。

这样的东西应该在你的测试中起作用:

moduleForComponent('tweet-composer', {
    beforeEach: function() {
        this.subject({
            store: {/*empty object*/}
        });
    }
});

如果部分测试依赖于从商店检索的数据,您可以执行以下操作:

this.subject({
    store: {
        find: function() {
          var mockedModel = Ember.Object.create({/*empty*/});
          return mockedModel;
        }
    }
});

这是为了保持“单元测试”的状态,如果你开始包含并注册你的应用程序中的其他对象,你将实际编写集成测试。

注意:

通常,直接在组件中查找模型是一种方法   反模式,你应该更喜欢传递你需要的任何模型   包含该组件的模板。

http://discuss.emberjs.com/t/should-ember-components-load-data/4218/2?u=givanse


12
2018-04-20 23:54



验收测试极其缓慢。如果我正在测试应用程序的许多方面,我更喜欢只使用它们。如果我正在测试两个部分,那么仅仅实例化这两个部分并将它们一起测试就更有意义了,但是与应用程序的其余部分隔离开来。 - Kevin Bullaughey
我知道你提到的那个帖子,我很欣赏这个建议,但是我在营地里觉得有一些有限的,适当的用途可以在某些组件中启用商店访问。特别是,当组件中表示的状态不是从URL派生时,而是组件的内在和隔离方面时,在组件中隔离此状态并且不污染具有该组件的所有路径是有意义的。实例化模型并将其更新为组件内部状态所需的逻辑更改。 - Kevin Bullaughey
同意,你有一个很好的观点。即使这样,在这种类型的测试(您的组件)中,您正在测试的是组件的逻辑而不是存储。因此,数据的来源并不重要。测试需要做的是验证不同的数据块是否触发了正确的事件并导致预期的输出。 - givanse
是的,虽然我正在使用 http-mocks 对于我的模型灯具,能够与真实的模拟数据一起测试组件是很好的,这些数据位于中心位置并且不会分布在我的所有数百个测试文件中。我意识到这意味着它本身并不是一个“单元测试”,但它是我认为最有用的测试粒度。我很感激你的回答,并且会对它进行投票,因为我学会了如何使用存根 subject,但我仍然坚持另一个让我做我想做的答案。 - Kevin Bullaughey