Angular语言 - 组件中订阅函数的单元测试失败



我花了很多时间试图找出一个解决方案没有张贴的东西,但我不明白什么是错的,所以我决定张贴问题。

下面是我要测试的文件:home.page.ts
import { Component, OnInit } from '@angular/core';
import { distinctUntilChanged } from 'rxjs/internal/operators/distinctUntilChanged';
import { AlertController, LoadingController } from '@ionic/angular';
import { DataService } from '../service/data.service';
import { League } from '../interfaces/League';
import { LeaguesImageLink } from '../types/leaguesImgLink.enum';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
searchTerm: string = '';
leaguesItems: League[] = [];
constructor(
private apiService: ApiService,
private route: ActivatedRoute,
private router: Router,
private dataService: DataService,
private loadingCtrl: LoadingController,
private alertController: AlertController
) { }
ngOnInit() {
this.loadLeagues();
}
async loadLeagues(): Promise<void> {
(await this.showSpinner()).present
this.apiService
.getAllLeagues()
.pipe(distinctUntilChanged())
.subscribe((res: League[]) => {
this.leaguesItems = res;
this.addImgLink();
});
(await this.showSpinner()).dismiss()
}
async showSpinner(): Promise<HTMLIonLoadingElement> {
const loading = await this.loadingCtrl.create({
message: 'Loading..',
spinner: 'bubbles',
});
return loading;
}
addImgLink(): void {
this.leaguesItems = this.leaguesItems.map((item: League) => {
return {
...item,
imgLink:
LeaguesImageLink[
item.name.split(' ').join('') as keyof typeof LeaguesImageLink
],
};
});
}
async showAlert(): Promise<void> {
const alert = await this.alertController.create({
header: "Alert",
message: "Il n'y a pas encore d'équipes !",
buttons: ['OK'],
});
await alert.present();
}
setLeaguesData(league: League): void {
if (league.teams?.length === 0) {
this.showAlert()
return;
} else {
this.dataService.setleaguesData(this.leaguesItems);
this.router.navigate(['../teams', league._id], {
relativeTo: this.route,
});
}
}
}

这里是我的测试文件home.page.spect.ts

import { MockLoadingController } from './../../mocks/IonicMock';
import { League } from './../interfaces/League';
import { mockLeagueArray, mockLeagueArrayImageLink } from './../../mocks/mockLeagues';
import { ApiService } from 'src/app/service/api.service';
import { FormsModule } from '@angular/forms';
import { Ng2SearchPipeModule } from 'ng2-search-filter/';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
waitForAsync,
} from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { HomePage } from './home.page';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { of } from 'rxjs';
fdescribe('HomePage', () => {
let component: HomePage;
let fixture: ComponentFixture<HomePage>;
let apiService: ApiService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [HomePage],
teardown: { destroyAfterEach: false },
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
IonicModule.forRoot(),
HttpClientTestingModule,
RouterTestingModule,
Ng2SearchPipeModule,
FormsModule,
],
providers: [
ApiService
]
}).compileComponents();
fixture = TestBed.createComponent(HomePage);
component = fixture.componentInstance;
apiService = TestBed.inject(ApiService)
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
it('should call ngOnInit', () => {
let loadLeagues = spyOn(component, 'loadLeagues');
component.ngOnInit();
expect(loadLeagues).toHaveBeenCalled();
});

it('should call getAllLeagues service and fill leaguesItems array', fakeAsync(() => {
//ARRANGE
spyOn(apiService, 'getAllLeagues').and.returnValue(of(mockLeagueArray))
//ACT
component.loadLeagues()
tick(1000)
fixture.detectChanges()
//ASSERT
expect(component.leaguesItems).toEqual(mockLeagueArray)
}))
});

my mock file:mockLeagues.ts

import { League } from "src/app/interfaces/League";
export const mockLeagueArray: League[] = [{
_id: "1",
name: "Supercopa de Espana",
sport: "sport1",
teams: ["t1", "t11"],
}, {
_id: "2",
name: "English Premier League",
sport: "sport2",
teams: ["t2", "t22"],
}]
export const mockLeagueArrayImageLink: League[] = [{
_id: "1",
name: "Supercopa de Espana",
sport: "sport1",
teams: ["t1", "t11"],
imgLink: "https://www.thesportsdb.com/images/media/league/badge/sp4q7d1641378531.png",
}, {
_id: "2",
name: "English Premier League",
sport: "sport2",
teams: ["t2", "t22"],
imgLink: "https://www.thesportsdb.com/images/media/league/badge/pdd43f1610891709.png",
}]

没什么特别的!当我运行ng test:

时,我得到的响应
Chrome 107.0.0.0 (Windows 10) HomePage should call getAllLeagues service and fill leaguesItems array FAILED
Expected $.length = 0 to equal 2.
Expected $[0] = undefined to equal Object({ _id: '1', name: 'Supercopa de Espana', sport: 'sport1', teams: [ 't1', 't11' ] }).
Expected $[1] = undefined to equal Object({ _id: '2', name: 'English Premier League', sport: 'sport2', teams: [ 't2', 't22' ] }).
at <Jasmine>
at UserContext.apply (src/app/home/home.page.spec.ts:81:36)
at UserContext.apply (node_modules/zone.js/fesm2015/zone-testing.js:2030:30)
at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:26)
at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:39)
Chrome 107.0.0.0 (Windows 10): Executed 3 of 12 (1 FAILED) (skipped 9) (0.799 secs / 0.601 secs)
TOTAL: 1 FAILED, 2 SUCCESS

我花了7天时间(阅读angular文档,上网查看…),现在我完成了,有人有解决方案吗?

谢谢。

present不应该有括号吗?

// !! Like this
(await this.showSpinner()).present();

同样,这个distinctUntilChanged什么也不做,因为它发出的是一个数组,每次它发出时,它将是一个新的数组。就像说[] === [],它总是假的,所以它总是释放。检查With Object Streams在这里:https://www.leonelngande.com/an-in-depth-look-at-rxjss-distinctuntilchanged-operator/但对你来说,它是一个数组。你可以做更多的研究,你可以在distinctUntilChanged中传递一个回调来微调什么时候你想要它发射,什么时候你不想。

如果我是你,我会这样改变loadLeagues:

async loadLeagues(): Promise<void> {
// (await this.showSpinner()).present
this.apiService
.getAllLeagues()
// !! This distinctUntilChanged does nothing since the source is an array
// .pipe(distinctUntilChanged())
.subscribe((res: League[]) => {
this.leaguesItems = res;
this.addImgLink();
});
// (await this.showSpinner()).dismiss()
}

注释掉this.showSpinner解散和呈现,看看测试是否通过。如果是这样,你就知道这两行可能是问题所在。

这是学习Angular单元测试的一个很好的资源:https://testing-angular.com/.

最新更新