1

我有一个方法和服务的组件,它可以运行一些组件的功能。如何测试Ember.js中的组件方法?

export default Ember.Component.extend({ 
    foo: false, 

    bar() { 
    this.set('foo', true); 
    }, 

    someService: Ember.inject.service('some-service'), 

    didInsertElement: function() { 
    const someService = this.get('someService'); 
    someService.registerComponent(this); 
    }, 
}); 

export default Ember.Service.extend({ 
    components: [], 
    registerComponent: function (component) { 
    let components = this.get('components'); 
    components.push(component); 
    }, 
    runBar(index) { 
    let components = this.get('components'); 
    components[index].bar(); 
    } 
}); 

1)如何为bar()方法编写测试?

2)还有我该如何编写这项服务的测试?

3)或者我该如何重构这种方法?

+0

还有什么我可以帮助你这个或你不喜欢我的答案的任何部分? – alptugd

回答

3

我会尽量按顺序回答你的问题;在开始之前,请查看以下twiddle我已经准备好了。我刚刚复制了你的组件和服务定义;还为该组件添加了willDestroyElement,并为该服务添加了unregisterComponent以进行必要的清理以从该服务中删除该组件。请注意清理工作;如果你完全不考虑,你会遇到很大的麻烦。关于你的问题;

1)您不得直接调用bar方法进行组件测试。你需要做的是渲染组件;检查一些断言;并调用服务的方法runBar,以便在集成测试中调用组件的bar方法。据我所知,这是你心目中的情景。请在我上面提供的旋转中查看my-component-test.js文件。在这个测试中的关键部分可能是

Ember.run(()=>Ember.getOwner(this).lookup('service:some-service').runBar(0)); 

代码片段。 Ember.getOwner(this).lookup()使您能够获取服务;请注意,您需要提供全名(service:some-service)才能获取它。它处于运行循环中;因为它应该有一个异步的影响,Ember警告你。无论如何;测试本身很简单,我猜;因为该组件所做的只是将foo属性打印到屏幕上,并且在调用服务的runBar方法时,该属性将从初始值false设置为true

2)用于测试服务;你可以写一个单元测试,这就是我在旋转中所做的。注意;你不需要实际的组件来注册服务;所以我使用了存根组件(在旋转中只有Ember.Object的虚拟实例)。其余的很容易遵循我相信。我只需调用服务的runBar方法并检查预期的断言。

3)现在这是一个难题;因为从你提供的代码片段中看到你的意图不容易做出这样的设计。尽管如此;我对重构的评论如下:尽可能避免将组件注册到其他构造(父组件,子组件,控制器,路由,服务等)。恕我直言,该组件的内部功能只能由组件本身调用。组件的接口应该是由组件触发的事件(我指的是从外部提供的动作)以及从外部传递的属性。我并不是说你的设计在任何情况下都应该避免。但只有在没有其他选项可行的情况下,才必须谨慎使用。主要原因是这样的;用这种设计来追溯代码应该成为一场噩梦。任何有权访问该服务的人都应该对组件(已注册到该服务)进行更新,该组件对其一无所知。这是我真正不喜欢的。我的建议是依赖定义良好的API,以便不传递它的组件并从不相关的地方对其进行更新。

这是一篇很长的文章;我希望它有帮助。

+0

非常感谢! 我会尽快尝试这种方法 –

+0

我的目标是创建加载微调组件,并通过微调器名称服务从不同组件触发动画。 Spinner组件可以放置在应用程序的任何位置以阻止某些内容的一部分。 这就是为什么我不知道更好的方式来管理所有spinners状态。 –