angular2 测试,我如何模拟子组件 [英] angular2 test, how do I mock sub component

查看:12
本文介绍了angular2 测试,我如何模拟子组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在 jasmine 测试中模拟子组件?

How do I mock sub component in jasmine tests?

我有 MyComponent,它使用 MyNavbarComponentMyToolbarComponent

I have MyComponent, which uses MyNavbarComponent and 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.

我知道如何使用 provide(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;

http://plnkr.co/edit/q1l1y8?p=preview

推荐答案

根据要求,我正在发布另一个关于如何使用 input/output 模拟子组件的答案:

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 是具有 [task] 输入和 (click) 输出的子组件.

app-task is a sub component with the [task] input and the (click) output.

好的,现在我们想为我的 TaskListComponent 编写测试,当然我们不想测试真正的 app-task 组件.

Ok great, now we want to write tests for my TaskListComponent and of course we don't want to test the real app-taskcomponent.

所以正如@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 测试,我如何模拟子组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆