【问题标题】:Angular 4 test fails when SetTimeout is used使用 SetTimeout 时 Angular 4 测试失败
【发布时间】:2017-08-18 17:16:06
【问题描述】:

我写了一个非常简单的测试,期望组件是真实的。它正在工作,但是一旦我在 oninit 中放置了一个 SetTimeOut,它就开始失败并出现以下问题。

错误:超时 - 未在超时内调用异步回调 由 jasmine.DEFAULT_TIMEOUT_INTERVAL 指定。

describe('AppComponent', () => {
  let appComponent: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async(() => {
    var errorMessages = new Array<ErrorMessage>();
    errorMessages.push(new ErrorMessage(500));

    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports: [
        RouterTestingModule,
        MessagesModule
      ],
      providers: [
        { provide: AuthService, useValue: TestHelper.createAuthServiceSpy() },
        { provide: ErrorHandlingService, useValue: TestHelper.createErrorHandlingServiceSpy(errorMessages) }
      ]
    }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    appComponent = fixture.debugElement.componentInstance;
    fixture.detectChanges();
  }));

  it('should create the app', async(() => {
    expect(appComponent).toBeTruthy();
  }));

  it('should show error in case of failure', async(() => {
    expect(appComponent.errorMessage.length).toBe(1);
  }));

  it('should get username for loggedin user', async(() => {
    expect(appComponent.username).toBe("username");
  }));
});

所有 3 个都失败了,当我评论 SetTimeOut 时它开始通过。

export class AppComponent implements OnInit {
    username: string = "";
    errorMessage: Message[] = [];
    showError: boolean = false;
    private activatedRoute: ActivatedRoute;
    constructor(public authService: AuthService, private renderer: Renderer, private errorhandlingService: ErrorHandlingService, private router: Router, private titleService: Title) {
        localStorage.removeItem(AppConstants.authenticationLocalStorageKey);
    }

    ngOnInit(): void {
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                var title = this.getTitle(this.router.routerState, this.router.routerState.root).join('-');
                this.titleService.setTitle(title);
            }
        });

        this.errorhandlingService.getErrors().subscribe(errorMessages => {
            let errorMessage: ErrorMessage = errorMessages.pop();
            this.errorMessage = errorMessage ? [{ severity: 'error', summary: `Error Code: ${errorMessage.statusCode}`, detail: `(${errorMessage.text})` }] : [];
            this.renderer.setElementProperty(document.body, "scrollTop", 0);
            this.showError = true;
            setTimeout(() => {
                this.showError = false;
            }, AppConstants.errorMessageFadeTime);
        });
        this.authService.getUsername().subscribe(data => this.username = data
            , error => this.errorhandlingService.handleError(error, 'could not get username'));
    }

    onDeactivate() {
        //scroll to top of page after routing
        this.renderer.setElementProperty(document.body, "scrollTop", 0);
    }

    private getTitle(state, parent) {
        var data = [];
        if (parent && parent.snapshot.data && parent.snapshot.data.title) {
            data.push(parent.snapshot.data.title);
        }

        if (state && parent) {
            data.push(... this.getTitle(state, state.firstChild(parent)));
        }
        return data;
    }


}

下面是html

<div>
        <div class="center-text">
            <div class="errorMessage" *ngIf="showError"><p-messages [value]="errorMessage"></p-messages></div>
            <router-outlet (deactivate)="onDeactivate()"></router-outlet>
        </div>
    </div>

我尝试了 fakesync 并完成了,但仍然出现同样的错误,有什么建议吗?

【问题讨论】:

    标签: javascript angular unit-testing asynchronous jasmine


    【解决方案1】:

    我建议你创建一个如下的假类,

    let errorOccured = false;
    
    class FakeAuthService {
        getErrors(){
         return Observable.of(errorOccured);
        }
    }
    
      providers: [
        { provide: AuthService, useClass: FakeAuthService},
    
      ]
    

    通过TestBedbeforeEach注入它

    authService = TestBed.get(AuthService);
    

    声明一个变量,如beforeEach async

    let authService : AuthService
    

    更新 1:

    将订阅完成事件中的setTimeOut 逻辑设为

    this.errorhandlingService.getErrors().subscribe(errorMessages => {
        let errorMessage: ErrorMessage = errorMessages.pop();
        this.errorMessage = errorMessage ? [{ severity: 'error', summary: `Error Code: ${errorMessage.statusCode}`, detail: `(${errorMessage.text})` }] : [];
        this.renderer.setElementProperty(document.body, "scrollTop", 0);
        this.showError = true;
    
    },error=>{},
    
    ()=>{
        setTimeout(() => {
            this.showError = false;
        }, AppConstants.errorMessageFadeTime);
    });
    

    【讨论】:

    • 您的建议有效,但我正在创建间谍。问题之一是测试需要进入错误订阅功能。像第二次测试。我已经更新了代码,以便您可以全面查看。也许重新写答案或解释?
    • 身份验证服务与失败的代码无关。错误消息服务的订阅者有 SetTimeOut()
    • 我想了解为什么使用setTimeOut
    • 因为我想在 5 秒后隐藏错误消息。如果我在用户点击 X 之前它不会一直留在那里。
    • 感谢您的建议,我刚刚尝试过,但它不起作用,这是有道理的,因为 finally 无论如何都会运行。我认为我们需要以某种方式告诉 Angular 等待 SetTimeout 完成(不确定)
    【解决方案2】:

    假设第二部分代码在您的实际服务中而不是测试中:

    Angular 提供的async 回调查找并等待异步代码,例如ObservablesPromisessetTimeouts。它会在检查答案之前尝试解析被测组件的方法调用。

    Jasmine 本身有一个名为DEFAULT_TIMEOUT_INTERVAL 的配置选项。在异步测试中(仅使用 jasmine,而不是 Angular 的测试工具),您可以将名为 done() 的方法传递到 it 块中,Jasmine 将等待一定的时间间隔以调用该方法。这是为了测试异步测试。默认超时为 5 秒,因此如果您调用 5000 的超时,由于 setTimeout 执行恶作剧,可能没有足够的时间让 Jasmine 检查。

    Angular 的 async 将 Jasmine done() 包装在一个不错的小调用中,它将在异步函数完成后执行测试。

    无论哪种方式,您都只想在异步的测试中使用async。如果测试没有异步结果,不要让测试等待一个。

    在您的情况下,您可以为异步测试设置一个 beforeEach 块,并将您的 asserts 包装在大于 5000 的超时中,或者您可以为这些测试更改 jasmine 配置:

    ... previous tests
    
    describe('timeout tests', () => {
    
      beforeEach(() => {
        jasmine.DEFAULT_TIMEOUT_INTERVAL = 5250;
      });
    
      it('should display error for five seconds', async(() => {
         ...tests
      }));
    
    });
    ... more tests
    

    【讨论】:

    • 感谢您的回答,我尝试了您的建议,但仍然失败...我认为它比我们想象的要棘手。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多