J'essaie d'écrire un test pour un service angular qui a une propriété Subject et une méthode pour appeler .next()
sur ce sujet.
Le service est le suivant:
@Injectable()
export class SubjectService {
serviceSubjectProperty$: Subject<any> = new Subject();
callNextOnSubject(data: any) {
this.serviceSubjectProperty$.next(data);
}
}
Et le fichier de test pour ce service:
import { TestBed, inject } from '@angular/core/testing';
import { SubjectService } from './subject.service';
describe('SubjectService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
SubjectService
]
});
});
it('callNextOnSubject() should emit data to serviceSubjectProperty$ Subject',
inject([SubjectService], (subjectService) => {
subjectService.callNextOnSubject('test');
subjectServiceProperty$.subscribe((message) => {
expect(message).toBe('test');
})
}));
});
Le test passe toujours l'événement si je change l'argument de subjectService.callNextOnSubject
de 'test'
à autre chose.
J'ai également essayé de tout emballer avec async
et fakeAsync
, mais le résultat est le même.
Quelle serait la bonne façon de tester si callNextOnSubject
émet des données vers le serviceSubjectProperty$
Matière?
J'ai trouvé cet article en recherchant la solution:
http://www.syntaxsuccess.com/viewarticle/unit-testing-eventemitter-in-angular-2.
et ça a bien marché pour moi (c'est très court, n'ayez pas peur de l'ouvrir).
Je le colle ici, alors peut-être que cela aidera ceux qui sont venus sur ce site à la recherche d'une réponse.
Concernant la question posée - je pense que vous devez changer:
subjectService.callNextOnSubject('test');
subjectServiceProperty$.subscribe((message) => {
expect(message).toBe('test');
})
à
subjectServiceProperty$.subscribe((message) => {
expect(message).toBe('test');
})
subjectService.callNextOnSubject('test');
, alors abonnez-vous d'abord, puis émettez un événement.
Si vous émettez 'test'
avant l'abonnement, rien ne "rattrapera" cet événement.
L'utilisation du rappel jasmine 'done' fera l'affaire jusqu'à présent, consultez la documentation ci-dessous: https://jasmine.github.io/api/Edge/global (voir implementationCallback (doneopt))
Ci-dessous un exemple utilisant votre cas de test:
it('callNextOnSubject() should emit data to serviceSubjectProperty$ Subject', (done) => {
inject([SubjectService], (subjectService) => {
subjectService.callNextOnSubject('test');
subjectServiceProperty$.subscribe((message) => {
expect(message).toBe('test');
done();
})
}) // function returned by 'inject' has to be invoked
});
Vous devez tester les données dont le composant a changé après l'appel de votre sujet. Devrait tester uniquement des variables publiques, non privées ou protégées; Par exemple:
un service:
@Injectable()
export class SomeService {
onSomeSubject: Subject<any> = new Subject();
someSubject(string: string) {
this.onSomeSubject.next(string);
}
}
composant:
export class SomeComponent {
@Input() string: string;
constructor(private service: SomeService) {
service.onSomeSubject.subscribe((string: string) => {
this.string = string;
}); //don't forget to add unsubscribe.
}
}
tester:
...
describe('SomeService', () => {
let someService: SomeService; // import SomeService on top
let someComponent: SomeComponent; // import SomeService on top
beforeEach(() => {
TestBed.configureTestingModule({
providers: [SomeService, SomeComponent]
});
injector = getTestBed();
someService = injector.get(SomeService);
someComponent = injector.get(SomeComponent);
});
describe('someSubject', () => {
const string = 'someString';
it('should change string in component', () => {
someService.someSubject(string);
expect(someComponent.string).tobe(string);
});
});
});