角单元测试永远不会达到断言

问题描述

我有一个搜索输入字段,该输入字段会在键入值后立即调用组件方法(“ searchBooks”)。

html

<form [formGroup]="searchForm">
  <mat-form-field>
    <input matInput type="search" formControlName="term"/>
  </mat-form-field>
</form>

组件

export class BookSearchComponent implements OnInit {
  searchForm = this.fb.group({
    term: ''
  });

  ...

  ngOnInit() {
    this.searchForm.get('term').valueChanges
    .subscribe(() => this.searchBooks()); // this subscription will listen to any value changes on the input field
  }

  searchBooks() {
     // does something
  }

我正在尝试编写一个单元测试,以检查在输入字段中输入值后是否调用了“ searchBooks”方法。当我尝试以下尝试时,测试永远不会达到断言

规格文件

describe('Search for Books',() => {
  let component: BookSearchComponent;
  let fixture: ComponentFixture<BookSearchComponent>;
  let searchInputField: ElementRef;
  let searchBooks: jasmine.Spy;

  beforeEach(async(() => {
    Testbed.configureTestingModule({
      imports: [BooksFeatureModule,NoopAnimationsModule,SharedTestingModule]
    }).compileComponents();

    component = fixture.componentInstance;
    fixture = Testbed.createComponent(BookSearchComponent);
    searchInputField = fixture.debugElement.query(By.css('input'));
    searchBooks = spyOn(component,'searchBooks');
    fixture.detectChanges();
  }));

  ...

  it('searchBooks method should be called after a value is entered in the search field',() => {
    searchInputField.nativeElement.value = 'Harry Potter';
    searchInputField.nativeElement.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      expect(component.searchBooks).toHaveBeenCalled(); // <--- Test runner never gets to this assertion!
    });
  });

对测试上述行为的实用方法有何建议? (在输入字段中输入值会触发searchBooks方法

解决方法

我认为您需要利用<ButtonMailto label="Write me an E-Mail" mailto="mailto:no-reply@example.com" /> 回调来让Angular / Jasmine知道何时完成测试。它不会进入done块中,因为它是异步的,并且测试将在回调发生之前完成。

尝试:

then

您也可以以it('searchBooks method should be called after a value is entered in the search field',(done) => { // add done call back as argument searchInputField.nativeElement.value = 'Harry Potter'; searchInputField.nativeElement.dispatchEvent(new Event('input')); fixture.detectChanges(); fixture.whenStable().then(() => { expect(component.searchBooks).toHaveBeenCalled(); // <--- Test runner never gets to this assertion! done(); // call done letting jasmine know I am done with my assertions }); }); 的方式进行操作(我更喜欢这样):

async/await

此外,由于您使用的是反应形式,因此反应形式的主要支持者是简化测试。您可以使用JavaScript设置表单的值并进行断言,而不必弄乱DOM。

it('searchBooks method should be called after a value is entered in the search field',async () => { // add async here
    searchInputField.nativeElement.value = 'Harry Potter';
    searchInputField.nativeElement.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    await fixture.whenStable(); // wait until the fixture is stable
    expect(component.searchBooks).toHaveBeenCalled(); // <--- Test runner never gets to this assertion!
  });