Как смоделировать функцию обратного вызова для проверки обещания с помощью жасмина в Angular 8 - PullRequest
0 голосов
/ 10 января 2020

У меня есть функция, которая возвращает обещание и вызывает другую функцию, которая принимает обратный вызов в качестве параметра, но я не могу понять, как имитировать функцию обратного вызова или функцию, вызывающую ее.

Я пытаюсь смоделировать функцию «listenOnAMessageWithCallBack» из службы, которую я внедряю, и я также хочу смоделировать вызываемую функцию.

Моя реализация:

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

и мой тест выглядит следующим образом:

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

При запуске теста я получаю следующую ошибку: Spy 'listenOnAMessageWithCallBack' получил вызов с аргументами ['catchUser', Function], но все настроенные стратегии указывают другие Аргументы.

Как я могу издеваться над функцией обратного вызова и ее вызывающей функцией?

Заранее спасибо.

1 Ответ

1 голос
/ 11 января 2020

Вы получаете это сообщение об ошибке, потому что вы настроили listenOnAMessageWithCallBack шпиона на .withArgs('message'), поэтому ваш шпион будет использоваться вместо этого метода только в том случае, если этот метод вызывается с аргументом 'message'. Однако в вашем сервисном коде этот метод вызывается с 'catchUser' и функцией обратного вызова, а не с 'message', поэтому ваш шпион никогда не вызывается. Если вы удалите условие .withArgs('message'), ваш шпион будет вызываться независимо от аргументов, переданных фактическому методу.

Как только вы добьетесь того, что ваш шпион будет вызван, в функции callFake шпиона вы сможете захватить обратный вызов, который передается в метод в коде вашего сервиса:

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

Вы не можете по-настоящему смоделировать обратный вызов, потому что это локальная переменная в вашем сервисе, но так как вы можете получить удержание этого и вручную вызовите его в своем тесте, вы сможете проверить его эффекты.

Вам нужно будет точно определить, что вы ожидаете, что ваш код будет делать, потому что этот обратный вызов устанавливает service.username на имя пользователя, переданное ему, но похоже, что в вашем тесте вы пытаетесь шпионить за service.stripDomain и вместо этого установить service.username. Похоже, вам нужно точно определить, что вы пытаетесь проверить здесь.

Вот блик стека , показывающий, как работает callFake, и предоставляющий вам доступ к функции обратного вызова.

...