OverrideComponent with TestBed

2020-07-16 06:56发布

问题:

I have MainComponent that uses ChildComponentA as a @ViewChild. MainComponent is calling a method on ChildComponentA.

I want to write an unit test case mocking ChildComponentA. How can I do this using TestBed (in Angular 2 RC5)?

Before I used to use overrideDirective(MainComponentName, ChildComponentA, MockChildComponentA); Is there an equivalent to this using TestBed?

I tried using

TestBed.overrideComponent(ChildComponentA,{
        set: {
          template: '<div></div>'
        }
      }); 

which just sets the template, but I want to mock the methods in the component as well.

回答1:

I think in this case you can try and replace the child component with a mock component. Just create a mock component with the same selector and use TestBed to remove the declaration of the real child component and add the declaration to your mock component.

@Component({
  selector: 'child',
  template: '<div></div>'
})
class MockComponent {

}

And in your test do this to use the mock component:

    TestBed.configureTestingModule({
        imports: [MyModule],
        declarations: [ParentComponent, MockComponent]
    });

    TestBed.overrideModule(MyModule, {
        remove: {
            declarations: [ParentComponent, ChildComponent],
            exports: [ParentComponent, ChildComponent]
        }
    });

More details here: https://github.com/angular/angular/issues/10689. Make sure to re-declare the ParentComponent, it does not work otherwise (not sure why).

If you use @ViewChild to get a reference to the child component, you will need to modify it to not use the type of the component, but an id. Use @ViewChild('child') instead of @ViewChild(ChildComponent). See second example from here: http://learnangular2.com/viewChild/



回答2:

Notice that if the ChildComponent is being declared in the TestModule itself, there is no need to override the module where the original was declared.

So, if your TestBed declaration looks like this:

TestBed.configureTestingModule({
    declarations: [
        ParentComponent,
        ChildComponent         // This is what you'd like to mock
    ]
});

Then, to override ChildComponent all you need is:

@Component({
    selector: 'child',
    template: '<div></div>'
})
class MockChildComponent {
}

TestBed.configureTestingModule({
    declarations: [
        ParentComponent,
        MockChildComponent      // Notice the original is replaced by the mock
    ]
});

As long as ChildComponent and MockChildComponent have the same selector, this one should work.

The other answer given for this question works for the cases the ChildComponent is being brought from a different module into the TestBed.

Note

If your ChildComponent has any @Input or @Output, then include those too in your MockChildComponent.