我想用Jest(^ v24.8.0)为Angular(〜v7.2.0)组件编写单元测试。
这是组件,它正在通过this.api.manageUser.getUsersStats()
使用嵌套服务,我想检查是否曾经调用过并模拟结果。因此,最好的办法是能够在“ 模拟”文件夹中编写“全局” /“手动”模拟。
我已经尝试了很多东西,但是都没有达到预期的效果。
我真的希望有人能帮助我!
// users.component
import { TstApiService } from '../../services/TstApi/TstApi.service';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.sass']
})
export class UsersComponent implements OnInit, OnDestroy {
constructor(
// ...
private api: TstApiService
) { }
ngOnInit() {
this.getUsersStats();
}
private getUsersStats() {
this.api.manageUser.getUsersStats().pipe(take(1)).subscribe(userStats => {
/* ... */ = userStats.allUsers
})
}
}
这是我的服务
// TstApi.service
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class TstApiService {
private http: TstHttp
manageUser: ManageUser
constructor(private httpClient: HttpClient) {
this.http = new TstHttp(this.httpClient)
this.manageUser = new ManageUser(this.http)
}
}
class ManageUser {
constructor(private http: TstHttp) {}
getUsersStats(): Observable<TUserStats> { //<-- this is the function used by the component
return this.http.get('/manage/user/stats')
}
}
class TstHttp {
private apiUrl: string
constructor(private http: HttpClient) {
this.apiUrl = environment.apiBaseUrl
}
/**
* @throws{ApiError}
* @throws{Error}
*/
get<T>(path: string): Observable<T> {
return this.http.get<T>(environment.apiBaseUrl + path)
}
}
这是规格文件:
/// <reference types='jest'/>
import { TestBed, ComponentFixture, inject } from '@angular/core/testing';
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { Router } from '@angular/router';
import { UsersComponent } from './users.component';
import { UsersService } from './users.service';
import { TstApiService } from "src/app/services/TstApi/TstApi.service";
// Approach No. 3
jest.mock("src/app/services/TstApi/TstApi.service")
// Approach No. 1
// jest.mock("src/app/services/TstApi/TstApi.service", () => {
// return jest.fn().mockImplementation(() => {
// return {manageUser: () => { getUsersStats: jest.fn() }};
// })
// });
describe('Users', () => {
@Component({ selector: 'app-input', template: '' }) class InputComponent {}
let router: Router;
let component: UsersComponent;
let fixture: ComponentFixture<UsersComponent>;
const http: HttpClient = new HttpClient(null);
let apiService: TstApiService = new TstApiService(http);
const usersService: UsersService = new UsersService(apiService);
let usersServiceMock;
// let tstApiServiceMock; // Approach No. 2
let httpMock: HttpTestingController;
beforeEach(async () => {
// Approach No. 2
// tstApiServiceMock = {
// manageUser: jest.fn().mockImplementation(() => ({
// getUsersStats: jest.fn().mockImplementation(() => Promise.resolve(null))
// }))
// }
await TestBed.configureTestingModule({
declarations: [
UsersComponent,
InputComponent
],
imports: [
HttpClientTestingModule,
RouterTestingModule.withRoutes([])
],
providers: [
// TstApiService
// { provide: TstApiService, useValue: tstApiServiceMock } // Approch No. 2
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
.compileComponents()
.then(() => {
// create component and test fixture
fixture = TestBed.createComponent(UsersComponent);
router = TestBed.get(Router)
// get test component from the fixture
component = fixture.componentInstance;
});
});
beforeEach(
// Approach No. 4
inject([TstApiService, HttpTestingController], (_service, _httpMock) => {
apiService = _service;
httpMock = _httpMock;
}));
test.only('Should getUsersStats on NgInit', () => {
expect(apiService.manageUser.getUsersStats).toHaveBeenCalled();
})
})
对于“方法3”,这是“手动”模型:
import { ManageUser, TstHttp, ErrorAlert } from './../TstApi.service';
// import { HttpClient } from '@angular/common/http';
// export const TstApiService = jest.genMockFromModule('../TstApi.service.ts');
export class TstApiService {
private http: TstHttp;
manageUser: ManageUser;
error: ErrorAlert;
constructor(private httpClient) {
this.error = new ErrorAlert();
this.http = new TstHttp(this.httpClient, this.error);
this.manageUser = new ManageUser(this.http);
}
}
答案 0 :(得分:0)
您可以尝试使用 ng-mocks
及其 MockBuilder
。
describe('suite', () => {
const getUsersStats = jest.fn(() => EMPTY);
beforeEach(() => {
// the 2nd param should be the module of UsersComponent
return MockBuilder(UsersComponent)
.mock(TstApiService, {
// because ManageUser is provided via `new` call,
// we need to provide a mock instance manually.
manageUser: MockService(ManageUser, {
getUsersStats,
}),
});
});
it('spec', () => {
MockRender(UsersComponent);
expect(getUsersStats).toHaveBeenCalled();
});
});