使用提供程序测试组件

Test component with a providers

我有一个服务 SoundPanelService 用于服务隔离场景(如 https://angular.io/guide/hierarchical-dependency-injection#scenario-service-isolation

@Injectable()
export class SoundPanelService {
  recorded = new Subject<Sound>();

  constructor() {
  }
}

我有 SoundPanelComponent

Component({
  selector: 'app-sound-panel',
  templateUrl: './sound-panel.component.html',
  styleUrls: ['./sound-panel.component.css'],
  providers: [SoundPanelService] // Service isolation 
})
export class SoundPanelComponent implements OnInit {
  recorded = new Subject<Sound>();

  constructor(private soundPanelService: SoundPanelService) {
    this.soundPanelService.recorded.subscribe((data) => {
      this.recorded.next(data);
    });
  }

  ngOnInit() {
  }

}

声音-panel.component.html

<app-sound-player></app-sound-player>
<app-sound-recorder></app-sound-recorder>

SoundPlayer 和 SoundRecorder 通过服务 SoundPanelService 与 soundpanel 通信。

我想测试 SoundPanelComponent

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';

import { SoundPanelComponent } from './sound-panel.component';
import { SoundRecorderComponent } from '../sound-recorder/sound-recorder.component';
import { SoundPlayerComponent } from '../sound-player/sound-player.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { SoundPanelService } from 'src/app/_services/sound-panel.service';
import { Sound } from 'src/app/_models/Sound';

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

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        SoundPanelComponent,
        SoundPlayerComponent,
        SoundRecorderComponent,
        SafeHtmlPipe
      ],
      imports: [HttpClientTestingModule],
      providers: [
      {
        provide: SoundPanelService, useClass: SoundPanelService
      }
      ]
    })
    .compileComponents();
  }));

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

  it('should emit sound on new record from sound panel service',  async () => {
    const s: Sound = {base64: 'data:base64', mimeType: 'audio/wmw'};
    spyOn(component.recorded, 'next').and.callThrough();
    sps = TestBed.get(SoundPanelService);
    sps.recorded.next(s);
    fixture.detectChanges();
    fixture.whenStable().then(res => {
expect(component.recorded.next).toHaveBeenCalledTimes(1);
    });
  });
   
});

但我收到错误

SoundPanelComponent > 应该在声音面板服务的新记录上发出声音 下一个预期的间谍已被调用一次。被调用0次

如果我让 SoundPanelService providedIn: 'root' 我设法通过了测试,但这不是我想要的,因为我希望 SoundPanelService 与每个 SoundPanelComponent 及其子组件隔离(我打算有很多 SoundPanelComponents在同一页上)。

如何测试这个?

已解决

用过这个Override component providers

必须将代码更改为:

  1. 引入了 .overrideComponent
 beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        SoundPanelComponent,
        SoundPlayerComponent,
        SoundRecorderComponent,
        SafeHtmlPipe
      ],
      imports: [HttpClientTestingModule]
    })
    .overrideComponent(SoundPanelComponent, {
      set: {
        providers: [
          { provide: SoundPanelService, useClass: SoundPanelService}
        ]
      }
    })
    .compileComponents();
  }));
  1. 从调试元素获取 SoundPanelService:
it('should emit sound on new record from sound panel service',  async () => {
    const s: Sound = {base64: 'data:base64', mimeType: 'audio/wmw'};
    spyOn(component.recorded, 'next').and.callThrough();
    sps = fixture.debugElement.injector.get(SoundPanelService) as SoundPanelService;
    sps.recorded.next(s);
    fixture.detectChanges();
    fixture.whenStable().then(res => {
      expect(component.recorded.next).toHaveBeenCalledTimes(1);
    });
  });

测试通过!