无法在模拟订阅方法中执行代码
Cannot execute code inside mocked subscribe method
在订阅方法中执行代码。
长话短说我正在测试检索 JWT token 的服务,我需要此 subscribe
中的代码在模拟 this.jwtService.getToken().subscribe(tokenResp =>
时执行,但它不执行。请参阅订阅内的评论:
被测系统:AuthenticationLibrary.service.ts:
getNewToken() {
var self = this;
if (self.busyGettingToken == false) {
self.busyGettingToken = true;
this.jwtService.getToken().subscribe(tokenResp =>
{
self.token = tokenResp.token<-------CODE NOT MAKING IT INTO HERE
self.busyGettingToken = false;
self.frontEndLoggingService.Log("getNewToken() Acquired: " + self.token, true);
});
}
}
isTokenValid() {
if (this.token == null)
{
return false;
}
else
{
var base64Url = this.token.split('.')[1];
var base64 = base64Url.replace('-', '+').replace('_', '/');
var jwt = JSON.parse(window.atob(base64));
if (jwt.exp >= this.configurationService.jwtRenewTime() / 1000) {
//Does not expire within the next x ms
return true;
} else {
//Expires within the next x ms
return false;
}
}
}
AuthenticationLibrary.service.spec.ts:
我正在将 this.jwtService.getToken()
部分模拟为 return :
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return {
subscribe: () => {<-------CODE MAKES IT INTO HERE
return new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
)
}
};
});
这是整个文件:
/// <reference path="../../typings/globals/es6-shim/index.d.ts"/>
/// <reference path="../../typings/globals/jasmine/index.d.ts" />
import { inject, TestBed, ComponentFixture } from "@angular/core/testing";
import { RouterTestingModule } from "@angular/router/testing";
import { Headers, HttpModule, BaseRequestOptions, XHRBackend, Response, Http, ResponseOptions } from "@angular/http";
import { MockBackend, MockConnection } from "@angular/http/testing";
import { Component, DebugElement } from "@angular/core";
import { By } from '@angular/platform-browser';
import "rxjs/add/operator/toPromise";
import { AuthenticationLibrary } from "../../app/services/authenticationLibrary.service";
import { ConfigurationService } from "../../app/services/configuration.service";
import { FrontEndLoggingService } from "../../app/services/frontEndLogging.service";
import { JwtService } from "../../app/services/jwt.service";
import { UtilitiesService } from "../../app/services/utilities.service";
describe("Authentication service", () => {
let mockBackend;
let jwtService;
let configurationService;
let http;
let feLogSvc;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
{ provide: XHRBackend, useClass: MockBackend },
ConfigurationService,
FrontEndLoggingService,
JwtService,
UtilitiesService
]
});
mockBackend = TestBed.get(XHRBackend);
jwtService = TestBed.get(JwtService);
configurationService = TestBed.get(ConfigurationService);
http = new Http(mockBackend, new BaseRequestOptions);
feLogSvc = TestBed.get(FrontEndLoggingService);
});
it("Should tell if token is valid", () => {
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
));
});
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return {
subscribe: () => {
return new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
)
}
};
});
let authLibService = new AuthenticationLibrary(
http,
configurationService,
feLogSvc,
jwtSvcSpy
);
authLibService.getNewToken();
expect(authLibService.isTokenValid()).toBe(true);
})
});
如何模拟 jwtService.getToken
以导致我的顶部代码块中 subscribe
方法中的代码执行?
您正在返回一个带有订阅函数的模拟,而不是一个带有接受回调的订阅函数的模拟 next
。就我个人而言,我会用包含您期望的确切数据的版本来存根 Observable:
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return Rx.Observable.of(new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
))
});
在订阅方法中执行代码。
长话短说我正在测试检索 JWT token 的服务,我需要此 subscribe
中的代码在模拟 this.jwtService.getToken().subscribe(tokenResp =>
时执行,但它不执行。请参阅订阅内的评论:
被测系统:AuthenticationLibrary.service.ts:
getNewToken() {
var self = this;
if (self.busyGettingToken == false) {
self.busyGettingToken = true;
this.jwtService.getToken().subscribe(tokenResp =>
{
self.token = tokenResp.token<-------CODE NOT MAKING IT INTO HERE
self.busyGettingToken = false;
self.frontEndLoggingService.Log("getNewToken() Acquired: " + self.token, true);
});
}
}
isTokenValid() {
if (this.token == null)
{
return false;
}
else
{
var base64Url = this.token.split('.')[1];
var base64 = base64Url.replace('-', '+').replace('_', '/');
var jwt = JSON.parse(window.atob(base64));
if (jwt.exp >= this.configurationService.jwtRenewTime() / 1000) {
//Does not expire within the next x ms
return true;
} else {
//Expires within the next x ms
return false;
}
}
}
AuthenticationLibrary.service.spec.ts:
我正在将 this.jwtService.getToken()
部分模拟为 return :
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return {
subscribe: () => {<-------CODE MAKES IT INTO HERE
return new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
)
}
};
});
这是整个文件:
/// <reference path="../../typings/globals/es6-shim/index.d.ts"/>
/// <reference path="../../typings/globals/jasmine/index.d.ts" />
import { inject, TestBed, ComponentFixture } from "@angular/core/testing";
import { RouterTestingModule } from "@angular/router/testing";
import { Headers, HttpModule, BaseRequestOptions, XHRBackend, Response, Http, ResponseOptions } from "@angular/http";
import { MockBackend, MockConnection } from "@angular/http/testing";
import { Component, DebugElement } from "@angular/core";
import { By } from '@angular/platform-browser';
import "rxjs/add/operator/toPromise";
import { AuthenticationLibrary } from "../../app/services/authenticationLibrary.service";
import { ConfigurationService } from "../../app/services/configuration.service";
import { FrontEndLoggingService } from "../../app/services/frontEndLogging.service";
import { JwtService } from "../../app/services/jwt.service";
import { UtilitiesService } from "../../app/services/utilities.service";
describe("Authentication service", () => {
let mockBackend;
let jwtService;
let configurationService;
let http;
let feLogSvc;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [
{ provide: XHRBackend, useClass: MockBackend },
ConfigurationService,
FrontEndLoggingService,
JwtService,
UtilitiesService
]
});
mockBackend = TestBed.get(XHRBackend);
jwtService = TestBed.get(JwtService);
configurationService = TestBed.get(ConfigurationService);
http = new Http(mockBackend, new BaseRequestOptions);
feLogSvc = TestBed.get(FrontEndLoggingService);
});
it("Should tell if token is valid", () => {
mockBackend.connections.subscribe(
(connection: MockConnection) => {
connection.mockRespond(new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
));
});
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return {
subscribe: () => {
return new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
)
}
};
});
let authLibService = new AuthenticationLibrary(
http,
configurationService,
feLogSvc,
jwtSvcSpy
);
authLibService.getNewToken();
expect(authLibService.isTokenValid()).toBe(true);
})
});
如何模拟 jwtService.getToken
以导致我的顶部代码块中 subscribe
方法中的代码执行?
您正在返回一个带有订阅函数的模拟,而不是一个带有接受回调的订阅函数的模拟 next
。就我个人而言,我会用包含您期望的确切数据的版本来存根 Observable:
let jwtSvcSpy = jasmine.createSpyObj('jwtService', ['getToken']);
jwtSvcSpy.getToken.and.callFake(() => {
return Rx.Observable.of(new Response(
new ResponseOptions({
body: {
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b3B0YWwuY29tIiwiZXhwIjoxNDI2NDIwODAwLCJodHRwOi8vdG9wdGFsLmNvbS9qd3RfY2xhaW1zL2lzX2FkbWluIjp0cnVlLCJjb21wYW55IjoiVG9wdGFsIiwiYXdlc29tZSI6dHJ1ZX0.yRQYnWzskCZUxPwaQupWkiUzKELZ49eM7oWxAQK_ZXw"
}
})
))
});