首页 > 解决方案 > Jasmine/Angular:测试 void EventEmitter onInit 的接收?

问题描述

我正在为我的一个组件编写单元测试。所述组件有一个visible布尔值,初始化为假。当所述布尔属性变为真时,组件的显示 css 属性从无变为阻塞,使其可见。

由于我的组件是子组件,因此我构建的循环以使父组件在技术上“触发”该组件如下:

    export class SidebarService {

    public toggleSidebar: EventEmitter<void> = new EventEmitter();
    
      constructor() {}

    public showSidebar() {
       this.toggleSidebar.emit();
      }
    }

该服务不需要连接到任何端点,也不需要返回任何数据:发射器充当子组件的“每次点击”信号。

 toggleSidebar() {
    this.sidebarService.showSidebar();
  }
     ngOnInit() {
        this.sidebarService.toggleSidebar.subscribe(() => {
          this.visible = true;
        });
      }

这样当父级触发事件发射器时,子级接收它并更改其visible属性。子组件有自己的手动方法将可见属性重置为 false。

从功能的角度来看,它完成了这项工作:当父组件单击按钮时,组件“出现”。但现在我担心我可能搞砸了他们关系的“连通性”方面。

在编写单元测试时,到目前为止,我对组件的了解如下:

describe('FilterSidebarComponent', () => {
  let component: FilterSideBarComponent;
  let fixture: ComponentFixture<FilterSideBarComponent>;

  const sidebarServiceSpy = jasmine.createSpyObj('SidebarService', [
    'showSidebar'
  ]);

  const fb: FormBuilder = new FormBuilder();

  configureTestSuite(() => {
    TestBed.configureTestingModule({
      imports: [
        MockModule(FormsModule),
        MockModule(ReactiveFormsModule),
        MockModule(TranslateModule.forRoot())
      ],
      declarations: [
        FilterSideBarComponent,
        CheckboxInputComponent,
        MockComponent(CountrySingleSearchComponent),
        MockComponent(UniversitiesSearcherComponent)
      ],
      providers: [
        {provide: SidebarService, useValue: sidebarServiceSpy},
        {provide: FormBuilder, useValue: fb},
      ]
    });
  });

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

到目前为止,唯一编写的测试(“应该创建”)失败了,Jasmine 告诉我:TypeError: Cannot read property 'subscribe' of undefined at at FilterSideBarComponent.subscribe [as ngOnInit]

我在 StackOverflow 中搜索了关于模拟服务订阅的方法的类似主题,但我发现的所有示例都使用返回对象、数据或 Observables 的服务。

当然我可以重写服务,只要它保留它的功能,但是 - 有没有一种有效的方法来测试像我这样的“服务”,或者我应该以某种方式重写服务?

标签: angularjasmine

解决方案


问题是您订阅了未在模拟服务中定义的 toggleSidebar 属性。我不确定 Jasmine 是否支持模拟属性,所以我将创建一个类似于下面的模拟对象。当您想触发您的事件进行测试时,您将执行 sideBarSubject.next()。

另外我不认为建议在服务中使用 EventEmitters。我也会更改您的服务以使用主题。

如果您以后需要监视新的模拟侧边栏服务,您可以执行 spyOn(sidebarServiceSpy, 'showSideBar') ,这是必要的,因为您不再将其创建为间谍。

describe('FilterSidebarComponent', () => {
  let component: FilterSideBarComponent;
  let fixture: ComponentFixture<FilterSideBarComponent>;


  let sideBarSubject = new Subject<void>();
  const sidebarServiceSpy = {
    toggleSidebar = sideBarSubject;
    showSidebar: Function(){}
  }

  const fb: FormBuilder = new FormBuilder();

  configureTestSuite(() => {
    TestBed.configureTestingModule({
      imports: [
        MockModule(FormsModule),
        MockModule(ReactiveFormsModule),
        MockModule(TranslateModule.forRoot())
      ],
      declarations: [
        FilterSideBarComponent,
        CheckboxInputComponent,
        MockComponent(CountrySingleSearchComponent),
        MockComponent(UniversitiesSearcherComponent)
      ],
      providers: [
        {provide: SidebarService, useValue: sidebarServiceSpy},
        {provide: FormBuilder, useValue: fb},
      ]
    });
  });

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

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

推荐阅读