Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing that items get filtered out of Observable (Jasmine/RxJS)

I'm doing unit testing with Jasmine/Karma against an Angular service. I'd like to confirm that my service properly filters items.

For example, if I have a service to get people over a certain age, it

  1. should return people over the minimum age (positive case)
  2. should NOT return people under a the minimum age (negative case)

It's #2 that I'm struggling to test.

The service:

    getPeople(minAge: number): Observable<string> {
        const source = Observable.from([
            { name: 'Joe', age: 30 },
            { name: 'Frank', age: 20 },
            { name: 'Ryan', age: 50 }
        ]);
        return source
            .filter(person => person.age >= minAge)
            .map(person => person.name);
    }

The Positive unit test

    it('should return people over 30', () => {
        const service = new MyService();
        const minAge = 30;
        service.getPeople(minAge).subscribe(people => {
            expect(people.length).toBeGreaterThan(0);
        });
    });

And the Negative unit test

it('should not return people over 55', () => {
        const service = new MyService();
        const minAge = 55;
        service.getPeople(minAge).subscribe(people => {
            expect(people.length).toBe(0); // WE NEVER GET HERE!
        });
    });

In the negative case, the Observable never returns anything, and rightly so. But, how do I write a unit test to confirm this?

like image 390
erin Avatar asked Jan 28 '23 19:01

erin


2 Answers

Your observable is a stream of values, you may do something like:

Positive:

let invoked = 0;
service.getPerson(30).subscribe(() => {
   invoked++;
})
expect(invoked).toEqual(2);

Negative:

let invoked = 0;
service.getPerson(55).subscribe(() => {
   invoked++;
})
expect(invoked).toEqual(0);
like image 118
Leandro Lima Avatar answered Jan 31 '23 23:01

Leandro Lima


Your first test is wrong. It tests that the length of each string being emitted is greater than 0. That shouldn't be what you test: the test would pass even if your code emitted 'Frank'. What you should test is that the emitted person names are 'Joe' and 'Ryan':

const result: Array<string> = [];
service.getPeople(minAge).subscribe(people => {
  result.push(people);
});
expect(result).toEqual(['Joe', 'Ryan']); 

Your second test isn't really necessary, since your first test checks that the filtering results the correct names, and doesn't return the incorrect ones. But if you really want to keep it, then you should fail the test if the subscribe callback is called, since it should not be called:

service.getPeople(minAge).subscribe(people => {
  fail('should not be called');
});
like image 44
JB Nizet Avatar answered Jan 31 '23 22:01

JB Nizet