【问题标题】:Angular unit test never reaches the assertionAngular 单元测试永远不会达到断言
【发布时间】:2020-09-09 19:45:24
【问题描述】:

我有一个搜索输入字段,只要输入一个值就会调用一个组件方法('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 方法)

【问题讨论】:

    标签: angular unit-testing jasmine karma-jasmine karma-runner


    【解决方案1】:

    我认为您需要利用 done 回调来让 Angular/Jasmine 知道您何时完成了测试。它不会进入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的方式(我更喜欢这种方式):

    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!
      });
    

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

    it('searchBooks method should be called after a value is entered in the search field', () => { 
        let term = component.searchForm.controls['term'];
        term.setValue('Harry Potter');
        expect(component.searchBooks).toHaveBeenCalled();
      });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-10
      • 1970-01-01
      相关资源
      最近更新 更多