繁体   English   中英

Angular2 - 使用debounceTime测试调用

[英]Angular2 - Testing call with a debounceTime

我正在使用一个表单控件来检测使用valueChangesdebounceTime更改。 我正在编写一个测试,它itemService以检查是否正在调用update方法。 如果我从表单控件中删除debounceTime ,测试工作正常。

这是组件中的表单控件。

this.itemControl.valueChanges.debounceTime(300).subscribe(response => {
   this.itemService.update(response);
});

这是测试

it('should do stuff',
    inject([ItemService], (itemService) => {
      return new Promise((res, rej) =>{
        spyOn(itemService, 'update');
        let item = {
            test: 'test'
        };
        fixture.whenStable().then(() => {
          let itemControl = new FormControl('test');
          fixture.componentInstance.itemControl = itemControl;
          fixture.autoDetectChanges();

          fixture.componentInstance.saveItem(item);
          expect(itemService.update).toHaveBeenCalled();

})}));

这是组件的saveItem函数

saveItem(item): void {
    this.itemControl.setValue(item);
}

就像我说的,如果我从表单控件中删除debounceTime ,测试执行正常,但我不能这样做。 我已经尝试在expect调用之前添加一个tick()调用,但我只是得到了这个错误

Unhandled Promise rejection: The code should be running in the fakeAsync zone to call this function ; Zone: ProxyZone ; Task: Promise.then ; Value: Error: The code should be running in the fakeAsync zone to call this function Error: The code should be running in the fakeAsync zone to call this function

你应该使用fakeAsync()tick() 查看下面代码 (.spec.ts文件),该代码根据您的测试代码成功运行。

代码说明如下:
fakeAsync()tick()应始终一起使用。 您可以一起使用async()/fixtureInstance.whenStable() ,但从程序员的角度来看,它不那么“可预测”。 我建议你尽可能使用fakeAsync()/tick() 当测试代码进行XHR调用(也就是测试Http请求)时,您应该使用async()/fixtureInstance.whenStable() )。

最好尽可能使用fakeAsync()/tick() ,因为您可以手动控制异步代码在测试代码中的运行方式。

正如您在下面的代码中看到的那样(.spec.ts文件)。 使用方法参数300tick(300)调用tick方法非常重要,因为您设置的去抖动值为300 如果您假设将去抖动值设置为500 ,那么您的测试代码中的刻度值应为500 ,如果您希望它在这种情况下通过。

您会注意到,如果设置tick(299)您的测试将失败,但这是正确的,因为您将去抖动值设置为300 这向您展示了使用fakeAsync()/tick()的强大功能,您可以控制代码的计时时间(当您使用fakeAsync()/tick()时,您是时间fakeAsync()/tick() )。


// component.sandbox.spec.ts
import { async, TestBed, fakeAsync, tick, inject } from "@angular/core/testing";
import { ReactiveFormsModule } from "@angular/forms";
import { SandboxComponent } from "./component.sandbox";
import { ItemService } from "../../Providers";
import "rxjs/add/operator/debounceTime";

describe("testFormControl", () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [ReactiveFormsModule],
      declarations: [SandboxComponent],
      providers: [ItemService],
    }).compileComponents();
  }));

  // The test you had questions about :)
  it("(fakeAsync usage) Should hit the ItemService instance's 'update' method once", fakeAsync(inject([ItemService], (itemService: ItemService) => {
    spyOn(itemService, "update");
    let fixture = TestBed.createComponent(SandboxComponent);
    fixture.detectChanges(); // It is best practices to call this after creating the component b/c we want to have a baseline rendered component (with ng2 change detection triggered) after we create the component and trigger all of its lifecycle events of which may cause the need for change detection to occur, in the case attempted template data bounding occurs.

    let componentUnderTest = fixture.componentInstance;

    componentUnderTest.saveItem("someValueIWantToSaveHEHEHE");

    tick(300); // avoliva :)

    expect(itemService.update).toHaveBeenCalled();

  })));

});

// component.sandbox.ts
import { Component, OnInit } from "@angular/core";
import { FormGroup, FormControl } from "@angular/forms";
import { ItemService } from "../../Providers";

@Component({
  template: `
    <form [formGroup]="formGroupInstance">
      <input formControlName="testFormControl" />
      <button type="submit">Submit</button>
      <button type="button" (click)="saveItem(formGroupInstance.controls['testFormControl'].value)">saveItem(...)</button>
    </form>
  `,
  styleUrls: ["component.sandbox.scss"],
})
export class SandboxComponent extends OnInit {
  public formGroupInstance: FormGroup;
  public testFormControlInstance: FormControl;

  constructor(private itemService: ItemService) {
    super();

    this.testFormControlInstance = new FormControl();

    this.formGroupInstance = new FormGroup(
      {
        testFormControl: this.testFormControlInstance,
      },
    );
  }

  public ngOnInit() {
    this.testFormControlInstance.valueChanges
      .debounceTime(300) // avoliva
      .subscribe((formControlInstanceValue: {}) => {
        this.itemService.update(formControlInstanceValue);
      });
  }

  public saveItem(item: any) {
    this.testFormControlInstance.setValue(item);
  }

}

// ../../Provider/index.ts
export class ItemService {
  public update(formControlInstanceValue: any) {
    // Makes http request to api to update item
    console.log(`HEY PROGRAMMER, YEAH YOU! :P \n => http request could have been made
    here to update an 'item' in the database.`);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM