Unit testing Angular 2单元测试组件,模拟内容子级

Unit testing Angular 2单元测试组件,模拟内容子级,unit-testing,typescript,angular,Unit Testing,Typescript,Angular,我正在Angular 2 RC4中实现一个向导组件,现在我正在尝试编写som单元测试。Angular 2中的单元测试开始得到很好的记录,但我无法找到如何在组件中模拟内容查询的结果 该应用程序有2个组件(除应用程序组件外)、WizardComponent和WizardStepComponent。应用程序组件(app.ts)定义向导及其模板中的步骤: <div> <fa-wizard> <fa-wizard-step stepTitle="First st

我正在Angular 2 RC4中实现一个向导组件,现在我正在尝试编写som单元测试。Angular 2中的单元测试开始得到很好的记录,但我无法找到如何在组件中模拟内容查询的结果

该应用程序有2个组件(除应用程序组件外)、WizardComponent和WizardStepComponent。应用程序组件(app.ts)定义向导及其模板中的步骤:

 <div>
  <fa-wizard>
    <fa-wizard-step stepTitle="First step">step 1 content</fa-wizard-step>
    <fa-wizard-step stepTitle="Second step">step 2 content</fa-wizard-step>
    <fa-wizard-step stepTitle="Third step">step 3 content</fa-wizard-step>
  </fa-wizard>
</div>
我创建了一个实现一个非常简单的向导来演示这个问题。wizard-component.spec.ts文件包含单元测试

如果有人能给我指出正确的方向,我将不胜感激。

多亏了您的回答,我才得以实现这一目标

关键是创建一个用于测试的包装器组件,该组件指定向导及其模板中的向导步骤。Angular随后将为您执行内容查询并填充变量

编辑:实现是为了Angular 6.0.0-beta.3

我的完整测试实现如下所示:

  //We need to wrap the WizardComponent in this component when testing, to have the wizard steps initialized
  @Component({
    selector: 'test-cmp',
    template: `<fa-wizard>
        <fa-wizard-step stepTitle="step1"></fa-wizard-step>
        <fa-wizard-step stepTitle="step2"></fa-wizard-step>
    </fa-wizard>`,
  })
  class TestWrapperComponent { }

  describe('Wizard component', () => {
    let component: WizardComponent;
    let fixture: ComponentFixture<TestWrapperComponent>;

    beforeEach(async(() => {
      TestBed.configureTestingModule({
        schemas: [ NO_ERRORS_SCHEMA ],
        declarations: [
          TestWrapperComponent,
          WizardComponent,
          WizardStepComponent
        ],
      }).compileComponents();
    }));

    beforeEach(() => {
      fixture = TestBed.createComponent(TestWrapperComponent);
      component = fixture.debugElement.children[0].componentInstance;
    });

    it('should set first step active on init', () => {
      expect(component.steps[0].active).toBe(true);
      expect(component.steps.length).toBe(3);
    });
  });
//测试时,我们需要将WizardComponent包装在此组件中,以初始化向导步骤
@组成部分({
选择器:“测试cmp”,
模板:`
`,
})
类TestWrapperComponent{}
描述('向导组件',()=>{
let组件:向导组件;
let夹具:组件夹具;
beforeach(异步(()=>{
TestBed.configureTestingModule({
模式:[无错误模式],
声明:[
TestWrapperComponent,
向导组件,
向导步骤组件
],
}).compileComponents();
}));
在每个之前(()=>{
fixture=TestBed.createComponent(TestWrapperComponent);
component=fixture.debugElement.children[0]。componentInstance;
});
它('应在初始化时将第一步设置为活动',()=>{
expect(component.steps[0].active).toBe(true);
期望(分量、步长、长度)toBe(3);
});
});
如果您有更好的/其他解决方案,欢迎您也添加您的答案。我将把这个问题留待一段时间。

@Component({
    @Component({
        selector: 'test-cmp',
        template: `<wizard>
                    <wizard-step  [title]="'step1'"></wizard-step>
                    <wizard-step [title]="'step2'"></wizard-step>
                    <wizard-step [title]="'step3'"></wizard-step>
                </wizard>`,
    })
    class TestWrapperComponent {
    }

    describe('Wizard Component', () => {
        let component: WizardComponent;
        let fixture: ComponentFixture<TestWrapperComponent>;
        beforeEach(async(() => {
            TestBed.configureTestingModule({
                imports: [SharedModule],
                schemas: [NO_ERRORS_SCHEMA],
                declarations: [TestWrapperComponent]
            });
        }));

        beforeEach(() => {
            fixture = TestBed.createComponent(TestWrapperComponent);
            component = fixture.debugElement.children[0].componentInstance;
            fixture.detectChanges();
        });

        describe('Wizard component', () => {
            it('Should create wizard', () => {
                expect(component).toBeTruthy();
            });
        });
});
选择器:“测试cmp”, 模板:` `, }) 类TestWrapperComponent{ } 描述('向导组件',()=>{ let组件:向导组件; let夹具:组件夹具; beforeach(异步(()=>{ TestBed.configureTestingModule({ 导入:[共享模块], 模式:[无错误模式], 声明:[TestWrapperComponent] }); })); 在每个之前(()=>{ fixture=TestBed.createComponent(TestWrapperComponent); component=fixture.debugElement.children[0]。componentInstance; fixture.detectChanges(); }); 描述('向导组件',()=>{ 它('应该创建向导',()=>{ expect(component.toBeTruthy(); }); }); });
对于最近提出这个问题的任何人来说,情况发生了轻微的变化,有一种不同的方法可以做到这一点,我发现这有点容易。它之所以不同,是因为它使用模板引用和
@ViewChild
来访问被测组件,而不是
fixture.debugElement.children[0]。componentInstance
。此外,语法也发生了变化

假设我们有一个select组件,它需要传入一个选项模板。我们想测试一下,如果没有提供选项模板,我们的
ngAfterContentInit
方法是否会抛出错误

以下是该组件的最低版本:

@Component({
  selector: 'my-select',
  template: `
    <div>
      <ng-template
        *ngFor="let option of options"
        [ngTemplateOutlet]="optionTemplate"
        [ngOutletContext]="{$implicit: option}">
      </ng-template>
    </div>
  `
})
export class MySelectComponent<T> implements AfterContentInit {
  @Input() options: T[];
  @ContentChild('option') optionTemplate: TemplateRef<any>;

  ngAfterContentInit() {
    if (!this.optionTemplate) {
      throw new Error('Missing option template!');
    }
  }
}
注意在测试组件中使用了
@ViewChild
装饰器。它允许以名称作为
TestComponent
类上的属性访问
MySelectComponent
。然后在测试设置中,声明
TestComponent
MySelectComponent

describe('MySelectComponent', () => {
  let component: MySelectComponent<number>;
  let fixture: ComponentFixture<WrapperComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      /* 
         Declare both the TestComponent and the component you want to 
         test. 
      */
      declarations: [
        TestComponent,
        MySelectComponent
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(WrapperComponent);

    /* 
       Access the component you really want to test via the 
       ElementRef property on the WrapperComponent.
    */
    component = fixture.componentInstance.mySelect;
  });

  /*
     Then test the component as normal.
  */
  describe('ngAfterContentInit', () => {
     component.optionTemplate = undefined;
     expect(() => component.ngAfterContentInit())
       .toThrowError('Missing option template!');
  });

});
description('MySelectComponent',()=>{
let组件:MySelectComponent;
let夹具:组件夹具;
beforeach(异步(()=>{
TestBed.configureTestingModule({
/* 
声明TestComponent和您想要的组件
测试。
*/
声明:[
测试组件,
myselect组件
]
})
.compileComponents();
}));
在每个之前(()=>{
fixture=TestBed.createComponent(包装器组件);
/* 
通过访问您真正想要测试的组件
包装器组件上的ElementRef属性。
*/
组件=fixture.componentInstance.mySelect;
});
/*
然后按正常情况测试部件。
*/
描述('ngAfterContentInit',()=>{
component.optionTemplate=未定义;
expect(()=>component.ngAfterContentInit())
.TothRowerr('缺少选项模板!');
});
});

我遇到了类似的问题,遇到了您的问题。在我自己搜索了一点之后,我发现了一篇帖子,他们说现在可以使用TestBed.createComponent(TypeOfComponent)使用@angular/core/testing的TestBed类来完成所有这些。也许这对其他有同样问题的人会有帮助。我只想强调一下关键部分,即SUT(
wizardComponentInstance
)引用。我尝试了完全相同的方法。但是,我在组件中的步骤仍然是空的。有什么想法吗?不鼓励只写代码的答案,因为它们不会为未来的读者提供太多信息。请对您所写的内容提供一些解释。谢谢发布。我想你的
TestComponent
是指
WrapperComponent
。此外,我还必须在组件分配()之后添加
fixture.detectChanges()
@Component({
  selector: 'my-select',
  template: `
    <div>
      <ng-template
        *ngFor="let option of options"
        [ngTemplateOutlet]="optionTemplate"
        [ngOutletContext]="{$implicit: option}">
      </ng-template>
    </div>
  `
})
export class MySelectComponent<T> implements AfterContentInit {
  @Input() options: T[];
  @ContentChild('option') optionTemplate: TemplateRef<any>;

  ngAfterContentInit() {
    if (!this.optionTemplate) {
      throw new Error('Missing option template!');
    }
  }
}
@Component({
  template: `
    <my-select [options]="[1, 2, 3]">
      <ng-template #option let-number>
        <p>{{ number }}</p>
      </ng-template>
    </my-select>
  `
})
class WrapperComponent {
  @ViewChild(MySelectComponent) mySelect: MySelectComponent<number>;
}
describe('MySelectComponent', () => {
  let component: MySelectComponent<number>;
  let fixture: ComponentFixture<WrapperComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      /* 
         Declare both the TestComponent and the component you want to 
         test. 
      */
      declarations: [
        TestComponent,
        MySelectComponent
      ]
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(WrapperComponent);

    /* 
       Access the component you really want to test via the 
       ElementRef property on the WrapperComponent.
    */
    component = fixture.componentInstance.mySelect;
  });

  /*
     Then test the component as normal.
  */
  describe('ngAfterContentInit', () => {
     component.optionTemplate = undefined;
     expect(() => component.ngAfterContentInit())
       .toThrowError('Missing option template!');
  });

});