gpt4 book ai didi

angular - [ Angular 7+] : How to unit test a service inside another service spec?

转载 作者:行者123 更新时间:2023-11-28 20:26:11 24 4
gpt4 key购买 nike

我有这两个服务文件,其中一个包含在另一个中。

app.service.ts

    import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { throwError, Observable } from 'rxjs';

import { catchError, map } from 'rxjs/operators';

import { Router } from '@angular/router';

import { environment } from '../../environments/environment';

import { AuthService } from '../_services/auth.service';

@Injectable({
providedIn: 'root'
})
export class AppService {

protected _apiURL = environment.apiURL;
// Define URLs here
_overviewURL: string;
_deleteUserUrl: string;

constructor(private http: HttpClient,
private _router: Router,
private _authService: AuthService) {
this.setApiUrl();
}

/* Begin: Misc services */
/**
* @description Sets the header for each request
* @param authorize Flag to whether include authorization token in headers or not
* @returns - Header consisting of Authorization token & Content-type
*/
setHeaders(authorize: boolean = false) {
const headers: any = {};
headers['Content-Type'] = 'application/json';

if (authorize && this._authService.isAuthenticated()) {
const authenticated = this._authService.getAuthenticatedUser();
headers.Authorization = `Bearer ${authenticated.idToken}`;
}
return {
headers: new HttpHeaders(headers)
};
}

/**
* @description Sets all the service URLs with the respective endpoints
*/
setApiUrl() {
this._overviewURL = this._apiURL + 'overview';
this._deleteUserUrl = this._apiURL + 'user/delete';
}

/**
* @description Gets the user overview page details based on BGtOccName & BGtID
* @param params - consists of BGtOccName & BGtId (BG Occupation Name & BG Occupation ID).
* Refer BG Docs: https://dev.burning-glass.com/docs/versions/3.3/getting-started
*/
getOverviewPageInfo(params: any) {
return this.http.post(this._overviewURL, params, this.setHeaders())
.pipe(
map(this.handleResponse),
catchError(this.handleError)
);
}

/**
* @description Delete an authenticated user
* @param user User object from localStorage
*/
deleteUser(user: any) {
return this.http.post(this._deleteUserUrl, user, this.setHeaders(true))
.pipe(
map(this.handleResponse),
catchError(this.handleError)
);
}


/**
* @description processes observable response
* @param res - takes in the response object
* @returns - data object
*/
private handleResponse = (res: any) => {
return res.data || {};
}

/**
* @description processes observable error
* @param error - takes in the error object
* @returns - error object
*/
private handleError = (error: Response | any) => {
console.error(error.error.message || error.message);
const errorMsg = error.error.message || error.message;
if (errorMsg === 'Invalid token') { this._router.navigate(['/login']); localStorage.removeItem('loggedUser'); }
return throwError(error.error.error);
}
}

auth.service.ts

    import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { environment } from '../../environments/environment';
import * as auth0 from 'auth0-js';

import { ToastrService } from 'ngx-toastr';

@Injectable({
providedIn: 'root'
})
export class AuthService {

private _idToken: string;
private _accessToken: string;
private _expiresAt: number;
private auth0User: any;

auth0 = new auth0.WebAuth({
clientID: environment.AUTH0_CLIENTID,
domain: environment.AUTH0_DOMAIN,
responseType: 'token id_token',
redirectUri: environment.AUTH0_REDIRECT_URI
});

constructor( public router: Router,
private _toastr: ToastrService) {
this.auth0User = JSON.parse(localStorage.getItem('auth0User'));
this._idToken = (this.auth0User && this.auth0User.idToken) ? this.auth0User.idToken : '';
this._accessToken = (this.auth0User && this.auth0User.accessToken) ? this.auth0User.accessToken : '';
this._expiresAt = (this.auth0User && this.auth0User.expiresAt) ? this.auth0User.expiresAt : 0;
}

get accessToken(): string {
return this._accessToken;
}

get idToken(): string {
return this._idToken;
}

public login(): void {
this.auth0.authorize();
}

public handleAuthentication(): void {
this.auth0.parseHash((err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.localLogin(authResult);
this.router.navigate(['/home']);
this._toastr.success(`You have been logged in!`, `Success`);
} else if (err) {
this.router.navigate(['/home']);
this._toastr.error(`Invalid login`, `Failed`);
}
});
}

private localLogin(authResult): void {
// Set the time that the access token will expire at
const expiresAt = (authResult.expiresIn * 1000) + Date.now();
this._accessToken = authResult.accessToken;
this._idToken = authResult.idToken;
this._expiresAt = expiresAt;
let auth0User: any = localStorage.getItem('auth0User');
if (auth0User) {
auth0User = JSON.parse(auth0User);
auth0User.idToken = authResult.idToken;
auth0User.expiresAt = expiresAt;
auth0User.accessToken = authResult.accessToken;
localStorage.setItem('auth0User', JSON.stringify(auth0User));
} else {
localStorage.setItem('auth0User', JSON.stringify({
idToken: authResult.idToken,
expiresAt: expiresAt,
accessToken: authResult.accessToken,
idTokenPayload: authResult.idTokenPayload
}));
}
}

public renewTokens(): void {
this.auth0.checkSession({}, (err, authResult) => {
if (authResult && authResult.accessToken && authResult.idToken) {
this.localLogin(authResult);
} else if (err) {
this._toastr.error(`Could not get a new token (${err.error}: ${err.error_description}).`, `Failed`);
this.logout();
}
});
}

public logout(): void {
// Remove tokens and expiry time
this._accessToken = '';
this._idToken = '';
this._expiresAt = 0;
localStorage.removeItem('auth0User');

this.auth0.logout({
returnTo: window.location.origin
});
this._toastr.success(`You have been logged out!`, `Success`);
}

public isAuthenticated(): boolean {
// Check whether the current time is past the
// access token's expiry time
return this._accessToken && Date.now() < this._expiresAt;
}

public getAuthenticatedUser() {
if (localStorage.getItem('auth0User')) {
return JSON.parse(localStorage.getItem('auth0User'));
} else {
return null;
}
}

}

每当我运行我的 app.service.spec.ts 测试文件时,它都会抛出与任何代码无关的错误。

app.service.spec.ts

    import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';

import { AppService } from './app.service';

describe('AppService', () => {
let service: AppService;
let httpMock: HttpTestingController;

beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule
],
providers: [AppService]
}));

beforeEach(() => {
service = TestBed.get(AppService);
httpMock = TestBed.get(HttpTestingController);
});

it('should be created', () => {
expect(service).toBeTruthy();
});

afterEach(() => {
httpMock.verify();
});

it('should retrieve overview details', () => {
const postParams = {
'designation': 'Fire Chief / Marshal',
'id': '378'
};

const overviewDetails = {
'data': {
'highSalary': 115511.77,
'estimatedSalary': 98935,
'nationalSalary': 98498.34,
'skills': [
{
'name': 'JavaScript Object Notation (JSON)',
'description': 'In computing, JavaScript Object Notation or JSON ( JAY-sn), is an open-standard ' +
'file format that uses human-readable text to transmit data objects consisting of' +
'attributevalue pairs and array data types (or any other serializable value).',
'count': 45084
},
{
'name': 'Software Architecture',
'description': 'Software architecture refers to the high level structures of a software system,' +
'the discipline of creating such structures, and the documentation of these structures.',
'count': 42676
}
],
'careers': [
{
'name': 'Chief Executive Officer',
'meanSalaryDiff': 11347.74
},
{
'name': 'Database Architect',
'meanSalaryDiff': 7699.84
}
]
}
};

service.getOverviewPageInfo(postParams).subscribe(overview => {
expect(overview).toEqual(overviewDetails.data);
});

const req = httpMock.expectOne(service._overviewURL);

expect(req.request.method).toBe('POST');

req.flush(overviewDetails);
});
});

但是如果删除这些行

if (authorize && this._authService.isAuthenticated()) {
const authenticated = this._authService.getAuthenticatedUser();
headers.Authorization = `Bearer ${authenticated.idToken}`;
}

从 app.service.ts 文件,然后所有测试工作正常(如您所见,它正在调用 authService 函数)。

我曾尝试将 authService 包含到 app.service.spec.ts 的提供者中,如下所示,但没有成功。 :(

beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule
],
providers: [AppService, AuthService]
}));

我的问题:如何在另一个可注入(inject)文件中包含/测试一个可注入(inject)(服务)?

最佳答案

我认为你需要为它提供一个模拟,除非你想做一个集成测试。例如,您尝试通过在 providers: [...] 列表中包含 AuthService 来修复它的方式将不起作用,除非您还添加了必要的文件构建您的 AuthService(即,您需要将 ToastrService 添加到您的提供者列表中。

我的建议是通过告诉 TestBed 使用您的模拟而不是实际的 AuthService 来模拟测试中的 AuthService。这是我所拥有的并且它通过了测试:

// in app.service.spec.ts

//imports

describe('AppService', () => {
let service: AppService;
let httpMock: HttpTestingController;

// Add your mock and all the methods/values you need.
// You can Spy on this object if you need to change the return values
// for different tests
let mockAuthSerice: any = {
isAuthenticated: () => true,
getAuthenticatedUser: () => {
return { user: 'bob', idToken: 'token' }
},
};

beforeEach(() => TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
RouterTestingModule
],
// Provide AuthServide but tell Angular to use the mock instead
providers: [
AppService,
{ provide: AuthService, useValue: mockAuthSerice }
]
}));

// ...rest of test file

});

关于angular - [ Angular 7+] : How to unit test a service inside another service spec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56221666/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com