javascript - Hur man mockar en callback-funktion för att testa ett löfte med jasmine i Angular 8


Jag har en funktion som returnerar ett löfte och kallar en annan funktion som tar en callback som parameter, men jag kan inte lista ut hur man mockar callback-funktionen eller funktionen som kallar den.

Funktionen jag försöker mocka är "listenOnAMessageWithCallBack" från en tjänst jag injicerar och jag vill också mocka callback-funktionen som den anropar.

Min implementation:

  async getUsername(): Promise<string> {
    return await new Promise<string>((resolve, reject) => {
      try {
        this.electronController.sendMessage('userName');
        let cb = (event, username) =>{
          this.username = username;
          let user = this.stripDomain(this.username);
          resolve(user);
        };
        this.electronController.listenOnAMessageWithCallBack('catchUser', cb); 
      } catch (err) {
        reject(err);
      }
    })
  }

och mitt test är följande:

  it('testing function with callback', async() => {
    const stripDomain = spyOn(service, 'stripDomain').and.callFake(()=>{
      service.username = service.username.split('\\').reverse()[0];
      return service.username;
    });
    let cb = (event, username)=>{Promise.resolve('username')}
    spyOn(electronController, 'listenOnAMessageWithCallBack').withArgs('message').and.callFake(()=>{});
    let username = await service.getUsername();
    expect(username).toBe('username');
    expect(stripDomain).toHaveBeenCalledTimes(1);
  });

Jag får följande fel när jag kör testet: Spy 'listenOnAMessageWithCallBack' fick ett samtal med argument [ 'catchUser', Funktion ] men alla konfigurerade strategier specificerar andra argument.

Hur kan jag mocka callback-funktionen och dess anropande funktion?

Tack i förväg.

Svar #1

Du får det felmeddelandet eftersom du konfigurerade din listenOnAMessageWithCallBack spion med .withArgs('message'), så din spion kommer bara att användas istället för den metoden om metoden anropas med argumentet 'message'. Men i din servicekod anropas den metoden med 'catchUser' och en callbackfunktion, inte med 'message', så din spion anropas aldrig. Om du tar bort .withArgs('message')-villkoret kommer din spion att anropas oavsett vilka argument som skickas till den faktiska metoden.

När du har fått det att fungera och din spion har anropats, kan du sedan inom spionens callFake-funktion få tag på callbacken som skickas in i metoden i din tjänstekod:

spyOn(electronController, 'listenOnAMessageWithCallBack').and.callFake(
  (msg, cb) => {
    expect(msg).toBe('catchUser');
    expect(typeof cb).toBe('function');

    // cb here is the cb being passed into listenOnAMessageWithCallBack in your service
    // code, so you need to invoke it here yourself or the promise won't get resolved
    cb('mockEvent', 'mockUsername');
  }
);

Du kan egentligen inte göra narr av callbacken eftersom det är en lokal variabel inom din tjänst, men eftersom du kan få tag på den och manuellt anropa den i ditt test, bör du kunna testa dess effekter.

Du skulle behöva lista ut exakt vad du förväntar dig att din kod ska göra, eftersom den callbacken sätter service.username till det användarnamn som skickas till den, men det ser ut som att du i ditt test försöker spionera på service.stripDomain och låta det sätta service.username istället. Så det verkar som att du behöver avgöra exakt vad du försöker testa här.

Här är en stackblitz som visar callFake fungerar och ger dig tillgång till callback-funktionen.

Relaterade artiklar