问题描述
如何在茉莉花测试中模拟子组件?
How do I mock sub component in jasmine tests?
我有 MyComponent
,它使用 MyNavbarComponent
和 MyToolbarComponent
import {Component} from 'angular2/core';
import {MyNavbarComponent} from './my-navbar.component';
import {MyToolbarComponent} from './my-toolbar.component';
@Component({
selector: 'my-app',
template: `
<my-toolbar></my-toolbar>
{{foo}}
<my-navbar></my-navbar>
`,
directives: [MyNavbarComponent, MyToolbarComponent]
})
export class MyComponent {}
当我测试这个组件时,我不想加载和测试那些两个子组件; MyNavbarComponent,MyToolbarComponent,所以我想模仿它。
When I test this component, I do not want to load and test those two sub components; MyNavbarComponent, MyToolbarComponent, so I want to mock it.
我知道如何使用提供模拟服务(MyService,useClass(...) )
,但我不知道如何模拟指令;组件;
I know how to mock with services using provide(MyService, useClass(...))
, but I have no idea how to mock directives; components;
beforeEach(() => {
setBaseTestProviders(
TEST_BROWSER_PLATFORM_PROVIDERS,
TEST_BROWSER_APPLICATION_PROVIDERS
);
//TODO: want to mock unnecessary directives for this component test
// which are MyNavbarComponent and MyToolbarComponent
})
it('should bind to {{foo}}', injectAsync([TestComponentBuilder], (tcb) => {
return tcb.createAsync(MyComponent).then((fixture) => {
let DOM = fixture.nativeElement;
let myComponent = fixture.componentInstance;
myComponent.foo = 'FOO';
fixture.detectChanges();
expect(DOM.innerHTML).toMatch('FOO');
});
});
这是我的plunker示例;
Here is my plunker example;
推荐答案
作为请求我发布了另一个关于如何使用输入模拟子组件的答案
/ 输出
:
As requested, I'm posting another answer about how to mock sub components with input
/output
:
所以让我们首先说我们有 TaskListComponent
显示任务,并在每次点击其中一个时刷新:
So Lets start by saying we have TaskListComponent
that displays tasks, and refreshes whenever one of them is clicked:
<div id="task-list">
<div *ngFor="let task of (tasks$ | async)">
<app-task [task]="task" (click)="refresh()"></app-task>
</div>
</div>
app-task
是一个子组件 [任务]
输入和(点击)
输出。
app-task
is a sub component with the [task]
input and the (click)
output.
好的,现在我们想为我的 TaskListComponent
编写测试,当然我们不想测试真正的 app-task
component。
Ok great, now we want to write tests for my TaskListComponent
and of course we don't want to test the real app-task
component.
所以@Klas建议我们可以配置我们的 TestModule
:
so as @Klas suggested we can configure our TestModule
with:
schemas: [CUSTOM_ELEMENTS_SCHEMA]
我们可能在构建或运行时都没有出现任何错误,但除了子组件的存在外,我们将无法测试更多错误。
We might not get any errors at either build or runtime, but we won't be able to test much other than the existence of the sub component.
那么我们如何模拟子组件?
首先我们将为子组件(相同的选择器)定义一个模拟指令:
First we'll define a mock directive for our sub component (same selector):
@Directive({
selector: 'app-task'
})
class MockTaskDirective {
@Input('task')
public task: ITask;
@Output('click')
public clickEmitter = new EventEmitter<void>();
}
现在我们将在测试模块中声明它:
Now we'll declare it in the testing module:
let fixture : ComponentFixture<TaskListComponent>;
let cmp : TaskListComponent;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TaskListComponent, **MockTaskDirective**],
// schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{
provide: TasksService,
useClass: MockService
}
]
});
fixture = TestBed.createComponent(TaskListComponent);
**fixture.autoDetectChanges();**
cmp = fixture.componentInstance;
});
- 请注意,因为灯具的子组件的生成是异步发生的在创建之后,我们激活其autoDetectChanges功能。
在我们的测试中,我们现在可以查询指令,访问其DebugElement的注入器,并通过它获取我们的模拟指令实例:
In our tests, we can now query for the directive, access its DebugElement's injector, and get our mock directive instance through it:
import { By } from '@angular/platform-browser';
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;
[此部分通常应位于 beforeEach
部分,更清洁的代码。]
[This part should usually be in the beforeEach
section, for cleaner code.]
从这里开始,测试是小菜一碟:)
From here, the tests are a piece of cake :)
it('should contain task component', ()=> {
// Arrange.
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
// Assert.
expect(mockTaskEl).toBeTruthy();
});
it('should pass down task object', ()=>{
// Arrange.
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;
// Assert.
expect(mockTaskCmp.task).toBeTruthy();
expect(mockTaskCmp.task.name).toBe('1');
});
it('should refresh when task is clicked', ()=> {
// Arrange
spyOn(cmp, 'refresh');
const mockTaskEl = fixture.debugElement.query(By.directive(MockTaskDirective));
const mockTaskCmp = mockTaskEl.injector.get(MockTaskDirective) as MockTaskDirective;
// Act.
mockTaskCmp.clickEmitter.emit();
// Assert.
expect(cmp.refresh).toHaveBeenCalled();
});
这篇关于angular2测试,我如何模拟子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!