Testable Observable
@ktrz__ | /ktrz
Chris Trześniewski
Developer 🥑 Advocate
& Senior Frontend Developer @Scalac
Why we do test
- Confidence
- Maintainability
- Guide the development (TDD)
- Documentation
How we test
const multiply = (a, b) => a * b;
describe('multiply function', () => {
it('should calculate properly', () => {
});
});
const input = {a: 3, b: 4};
const expected = 12;
const result = multiply(input.a, input.b);
expect(result).toEqual(expected);
How we test
- Test Observables the same?
- `notNull` operator
- filters null values
Testing Observables
describe('notNull operator', () => {
it('should filter null values', () => {
});
});
const source = from([1, null, 2]);
const result = source.pipe(notNull);
const spy = createSpy();
result.subscribe(spy);
expect(spy).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledWith(1);
expect(spy).toHaveBeenCalledWith(2);
Testing Observables
- Are we done?
- ...not really
What's an Observable
- Data delivered over time
- Can be synchronous
- or asynchronous
Second test
describe('notNull operator', () => {
it('should filter null values - async', () => {
});
});
const source =
from([1, null, 2], asyncScheduler);
const result = source.pipe(notNull);
const spy = createSpy();
result.subscribe(spy);
expect(spy).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledWith(1);
expect(spy).toHaveBeenCalledWith(2);
describe('notNull operator', (done) => {
it('should filter null values - async',
(done) => {
});
});
const source =
from([1, null, 2], asyncScheduler);
const result = source.pipe(notNull);
const spy = createSpy();
result.subscribe({
next: spy,
complete: () => {
}
});
expect(spy).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledWith(1);
expect(spy).toHaveBeenCalledWith(2);
done();
done
Async tests - pitfalls
- Test end awareness
- Can be long
const source =
from([1, null, 2], asyncScheduler)
.pipe(delay(3000));
Fake async tests
const source = from([1, null, 2])
.pipe(delay(3000));
const result = source.pipe(notNull);
const spy = createSpy();
result.subscribe(spy);
expect(spy).toHaveBeenCalledTimes(0);
tick(3000);
expect(spy).toHaveBeenCalledTimes(2);
expect(spy).toHaveBeenCalledWith(1);
expect(spy).toHaveBeenCalledWith(2);
Fake async tests
- Synchronous
- Full control over time
- Fast
Marble testing
- Visual representation
- Intuitive
- Fast
Marble testing
it('should filter null values - marbles',
marbles((m: Context) => {
}));
const sor = '--x--y--z|';
const exp = '--1-----2|';
const values = {x: '1', y: null, z: '2'};
const source$ = m.cold(s, values);
const expected$ = m.cold(exp);
const result$ = source.pipe(notNull);
m.expect(result).toBeObservable(expected);
More examples
Summary
- Observables - sync & async
- 3 ways to test
- async - with done function
- fake async - manually control time
- marble testing - visually
Thank you!
Any questions?
Testable Observable
By Chris Trześniewski
Testable Observable
- 287