javascript - Cum să spionezi metodele unui serviciu atunci când serviciul este furnizat în rădăcina unui component
Scriu teste unitare pentru un component Angular folosind karma-jasmine. Am folosit providers în ProfileComponent-ul meu și am injectat ProfileService.
profile.component.ts
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss'],
providers: [ProfileService]
})
export class ProfileComponent implements OnInit {
public data;
constructor(private profileService: ProfileService) {}
ngOnInit() {
await this.profileService.login();
this.profileService.getData('A').subscribe((result) => {
this.data = result;
});
}
}
profile.service.ts
@Injectable()
export class ProfileService {
private baseUrl: string;
constructor(private http: HttpClient) {
this.baseUrl = 'https://localhost:4002';
}
public async login() {
const loginUrl = `${this.baseUrl}/api/Login`;
return this.http.post(loginUrl, {}, { headers }).toPromise();
}
getData(id: string) {
const url = `${this.baseUrl}/api/GetData/${id}`;
return this.http.get(url, { headers });
}
}
profile.component.spec.ts
const data = ['A', 'B', 'C'];
describe('Client.App.ProfileComponent', () => {
let component: ProfileComponent;
let fixture: ComponentFixture < ProfileComponent > ;
let profileService: ProfileService;
let profileData;
beforeEach(async (() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ProfileService],
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
}));
beforeEach(fakeAsync(() => {
profileData = new Subject();
profileService = TestBed.inject < ProfileService > (ProfileService);
spyOn(profileService, 'login').and.returnValue({});
spyOn(profileService, 'getData').and.returnValue(profileData);
fixture = TestBed.createComponent(ProfileComponent);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('shall create the component', () => {
profileData.next(data);
fixture.detectChanges();
expect(component).toBeDefined();
});
});
Am adăugat un debugger și am verificat că eșuează la autentificare. Deci, am două întrebări:
- Deoarece am folosit furnizori în
Profile Component, pot să injectezProfileServiceîn fișierulprofile.component.spec.tsdeoarece va crea două instanțe ale aceluiași serviciu? - Cum să spionezi login() și getData() din ProfileService dacă afirmația de mai jos nu funcționează...?
spyOn(profileService, 'login').and.returnValue({});
Te rog să mă ajuți cu asta.
Răspuns #1
- Deoarece am folosit furnizori în Componenta Profilului, pot să injectez ProfileService în fișierul profile.component.spec.ts, deoarece asta va crea două instanțe ale aceluiași serviciu..??
Răspuns: Ar trebui să creezi un Stub pentru serviciu pentru a înlocui dependența de ProfileService real folosind useClass
export class ProfileServiceStub {
getData(id: string) {
return of({some_obj: "value"})
}
}
și în spec.ts
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, ReactiveFormsModule, RouterTestingModule],
declarations: [ProfileComponent],
providers: [ {provide: ProfileService , useClass: ProfileServiceStub } ], // <-- useclass here
schemas: [NO_ERRORS_SCHEMA]
}).compileComponents();
- Cum să spionezi login() și getData() din ProfileService, deoarece declarația de mai jos nu funcționează...?
Răspuns: Faceți serviciul public în constructorul componentului, astfel:
constructor(public profileService: ProfileService) { }
V-aș recomanda cu tărie să citiți articolul meu despre ceva similar, în care am testat componenta
Răspunsul #2
1.) Cred că ceea ce ai este în regulă, punerea ProfileService în array-ul provider din TestBed.configureTestingModule este bine și atunci când componenta este creată, știe cum să-l creeze. De fiecare dată când componenta este creată, va fi un furnizor separat, dar acesta va fi cazul fie că furnizezi provider-ul în componentă sau global, deoarece un test construiește și distruge (beforeEach.... TestBed.configureTestingModule....).
2.) Încearcă `spyOn(profileService, 'login').and.returnValue(Promise.resolve({}));`
Notă: ngOnInit are nevoie de un decorator async pentru a putea folosi await.
