如何在没有方法的Angular中存根导入的模块?

Nic*_*cky 3 unit-testing jasmine typescript karma-jasmine angular

我有一个使用Jasmine Testing Framework的Angular应用程序。该应用程序有一个称为的服务AuthService,用于处理JSON Web令牌的解码:

验证服务

import * as jwtDecode from 'jwt-decode';
...

@Injectable()
export class AuthService {
  ...
  public getTokenPayload(token) {
    return jwtDecode(token);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,我想对模块进行存根jwtDecode并为测试目的返回一个假值:

认证服务规范

...

it('should get a token payload', () => {
  const fakeToken = 'fake-token';

  spyOn(service, 'getTokenPayload').and.callThrough();
  const tokenPayload = service.getTokenPayload(fakeToken);

  expect(tokenPayload).toBe('fake-token');
});
Run Code Online (Sandbox Code Playgroud)

因为'fake-token'不是有效的JSON Web令牌,所以测试失败并显示以下消息:

InvalidTokenError: Invalid token specified: undefined is not an object (evaluating 'str.replace')
Run Code Online (Sandbox Code Playgroud)

这可能是jwt-decode模块产生的错误,这是预料之中的。我不想为了创建用于测试目的的有效JSON Web令牌而包含另一个模块。相反,我想对的功能进行存根jwtDecode()

我尝试过的

1.使用spyOnjwtDecode

当我使用时spyOn,我需要一个带有方法的对象。因此,对于导入的文件而言jwtDecode,这是行不通的,因为它本身是一个函数:

spyOn(jwtDecode, '<method?>').and.callFake(() => 'fake-token');
Run Code Online (Sandbox Code Playgroud)

2. callFake在上使用getTokenPayload

我试过使用:

spyOn(service, 'getTokenPayload').and.callFake(() => 'fake-token');
Run Code Online (Sandbox Code Playgroud)

...这可以防止发生任何错误。但是,我的代码覆盖率报告现在显示该功能getTokenPayload未被覆盖。此外,我在使用外部NPM模块应用中的其他功能,我不想忽略代码覆盖率,因为他们可能需要测试的方法内其他实现。

3. createSpy在上使用jwtDecode

我试图覆盖导入jwtDecode并创建一个间谍:

const jwtDecode = jasmine.createSpy('jwtDecode').and.returnValue('fake-token');
Run Code Online (Sandbox Code Playgroud)

这给了我与上面相同的错误,表明jwtDecode在我的实际AuthService服务中没有被覆盖。

4.使用window作为对象

这个问题,我读到全局模块可能附加到window对象。因此,我尝试对以下操作执行相同的操作jwt-decode

在测试中...

console.log(window.jwtDecode); // undefined
console.log(window.jwt_decode); // undefined
Run Code Online (Sandbox Code Playgroud)

不幸的是,两个值都undefinedwindow对象上。

我想总的来说问题变成了:

如何存根导入的NPM模块?特别是,如果它们不是对象而是函数(如何在Jasmine中使用方法spyOn),则如何将它们存根?

vin*_*nce 5

你很亲密!由于服务只是一类,因此测试它的最佳方法是实例化一个新的服务并对其进行监视,就像您正在做的那样。如果您想监视导入的方法,则需要以某种方式将其包括在服务中。否则,您的测试将无法知道该方法是什么。

因此,请为您的服务设置属性:

jwtDecode = jwtDecode; // the imported one
Run Code Online (Sandbox Code Playgroud)

并按照this.jwtDecode您的getTokenPayload方法进行调用。

然后,以下将起作用:

const service = new AuthService( /* constructor args */ );

const jwtDecode = spyOn(service, 'jwtDecode');
jwtDecode.and.returnValue('fake-token');
Run Code Online (Sandbox Code Playgroud)