【问题标题】:Angular Test Mock ContentChildAngular 测试模拟 ContentChild
【发布时间】:2021-06-17 03:03:30
【问题描述】:

我想测试一个 Angular 组件并将 contentChild 替换为 Mock。我遵循了这个指南:https://medium.com/angular-in-depth/angular-unit-testing-viewchild-4525e0c7b756 该指南适用于 viewChild,但我认为这也适用于内容 Child。

我的 contentChild 有一个父订阅的 Observable。如果我用真正的孩子测试代码,它就可以工作。如果我嘲笑孩子,测试就不起作用。我认为我在测试中查询以发出新值的子模拟是一个不同的实例,而不是父订阅的那个。

我的父母:

@Component({
  // tslint:disable-next-line:component-selector
  selector: '[appParent]',
  template: `
    <div>
      <span class="true" *ngIf="display$ | async; else other">True</span>
    </div>
    <ng-content></ng-content>
    <ng-template #other><span class="false">False</span></ng-template>
  `
})
export class ParentComponent implements AfterContentInit {

  @ContentChild(ChildComponent) child!: ChildComponent;

  display$: Observable<boolean>;

  ngAfterContentInit(): void {
    this.display$ = this.child.display$;
  }
}

我的模拟:

@Component({
  selector: 'app-child',
  template: '',
  providers: [
    {
      provide: ChildComponent,
      useExisting: ChildStubComponent
    }
  ]
})
export class ChildStubComponent {
  displaySubject = new BehaviorSubject(false);
  display$: Observable<boolean> = this.displaySubject.asObservable();
}

还有测试:

describe('ParentComponentTest', () => {
  @Component({
    template: `
      <div appParent>
        <app-child></app-child>
      </div>
    `
  })
  class TestComponent {
    @ViewChild(ChildStubComponent)
    child!: ChildStubComponent;
  }

  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [
        TestComponent,
        ChildStubComponent,
        ParentComponent
      ]
    }).compileComponents();
  });

  beforeEach(async () => {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should find true', () => {
    component.child.displaySubject.next(true);
    fixture.detectChanges();
    expect(fixture.debugElement.query(By.css('.true'))).toBeTruthy();
  });

});

【问题讨论】:

    标签: angular unit-testing mocking angular-content-projection


    【解决方案1】:

    您可以使用具有模拟功能的测试库,例如 ng-mocks

    它提供MockBuilderMockComponent

    它还有MockInstance,允许您在初始化之前模拟组件的方法/属性。

    我认为你的情况类似于How to test a ViewChild / ViewChildren of a declaration

    您的测试可能如下所示:

    describe('ParentComponentTest', () => {
      // keeping ParentComponent as it is and mocking ChildStubComponent
      beforeEach(() => MockBuilder(ParentComponent).mock(ChildStubComponent));
    
      it('should find true', () => {
        // providing a mock upfront
        const displaySubject = MockInstance(
          ChildStubComponent,
          'displaySubject',
          new Subject(),
        );
    
        // rendering desired template
        const fixture = MockRender(`
          <div appParent>
            <app-child></app-child>
          </div>
        `);
    
        // testing behavior
        displaySubject.next(true);
        fixture.detectChanges();
        expect(ngMocks.find('.true')).toBeTruthy();
      });
    });
    

    【讨论】:

    • 这可能行得通,但在我们的项目中,我们希望安装尽可能少的包,并且我们认为应该可以在没有新包的情况下进行模拟。
    • 同样的 web 应用程序也可以不用 react 和 angular :)
    【解决方案2】:

    问题接缝是,你得到的 view-child 不是正确的实例。解决方法是从父组件的子属性中获取实例。

    
    describe('ParentComponentTest', () => {
      @Component({
        template: `
          <div appParent>
            <app-child></app-child>
          </div>
        `
      })
      class TestComponent {
        @ViewChild(ParentComponent)
        parent!: ParentComponent;
      }
    
      let component: TestComponent;
      let fixture: ComponentFixture<TestComponent>;
    
      ....
    
      it('should find true', () => {
        const childStub = component.parent.child.toArray()[0] as unknown as ChildStubComponent;
        childStub.displaySubject.next(true);
        fixture.detectChanges();
        expect(fixture.debugElement.query(By.css('.true'))).toBeTruthy();
      });
    
    });
    
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-19
      • 2018-11-24
      相关资源
      最近更新 更多