我有一个使用Jasmine测试框架的Angular应用程序。该应用程序有一个名为AuthService
的服务,用于处理JSON Web令牌的解码:
auth.service.ts
import * as jwtDecode from 'jwt-decode';
...
@Injectable()
export class AuthService {
...
public getTokenPayload(token) {
return jwtDecode(token);
}
}
现在我想将模块jwtDecode
存根并在测试时返回一个伪值:
auth.service.spec.ts
...
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');
});
由于'fake-token'
不是有效的JSON Web令牌,因此我的测试失败并显示以下消息:
InvalidTokenError: Invalid token specified: undefined is not an object (evaluating 'str.replace')
这可能是jwt-decode
模块生成的错误,这是预期的。我不想仅仅为了测试目的而包含另一个模块来创建有效的JSON Web令牌。相反,我想要保留jwtDecode()
的功能。
spyOn
jwtDecode
当我使用spyOn
时,我需要一个带方法的对象。因此,对于导入的jwtDecode
,这不会起作用,因为它本身就是一个函数:
spyOn(jwtDecode, '<method?>').and.callFake(() => 'fake-token');
callFake
getTokenPayload
我尝试过使用:
spyOn(service, 'getTokenPayload').and.callFake(() => 'fake-token');
...这可以防止任何错误发生。但是,我的代码覆盖率报告现在显示函数getTokenPayload
未涵盖。此外,我在应用程序中还有其他使用外部NPM模块的功能,我不想忽略代码覆盖,因为它们可能在应该测试的方法中有其他实现。
createSpy
jwtDecode
我尝试重写导入的jwtDecode
并创建一个间谍:
const jwtDecode = jasmine.createSpy('jwtDecode').and.returnValue('fake-token');
这给了我与上面相同的错误,表示我的实际jwtDecode
服务中未覆盖AuthService
。
window
作为对象从this question我读到全局模块可能附加到window
对象。因此,我尝试为jwt-decode
做同样的事情:
...
console.log(window.jwtDecode); // undefined
console.log(window.jwt_decode); // undefined
不幸的是,undefined
对象上的两个值均为window
。
我猜一般来说问题就变成了:
如何存根导入的NPM模块?特别是,如果它们不是一个对象,而是一个函数(没有在Jasmine spyOn
中使用的方法),如何对它们进行存根?
答案 0 :(得分:4)
你非常接近!由于服务只是一个类,因此测试它的最佳方法是实例化一个新的并监视它,就像你正在做的那样。 如果您想监视导入的方法,则需要以某种方式将其包含在您的服务中。否则,您的测试无法知道该方法是什么。
所以你的服务有一个属性:
jwtDecode = jwtDecode; // the imported one
并在this.jwtDecode
方法中将其称为getTokenPayload
。
然后以下内容将起作用:
const service = new AuthService( /* constructor args */ );
const jwtDecode = spyOn(service, 'jwtDecode');
jwtDecode.and.returnValue('fake-token');
答案 1 :(得分:0)
只需监视 default
模块中的 jwt-decode
导出,即 jwtDecode
函数。这样就不必按照建议污染您的服务。
例如,在您的规范文件中:
import * as jwt from 'jwt-decode';
...
// return whatever data structure you require
spyOn(jwt, 'default').and.returnValue({ someData: ['x', 'y', 'z'] });