Share
Embed
Testing, tEstIng, TeStInG or how to test React apps with generated input data
Olena Sovyn
April 25, 2020
Transcript
29 slides
-
Olena Sovyn @frontendgirl Testing, tEstIng, TeStInG or how to test
React apps with generated input data -
Olena Sovyn • Senior software engineer/tech lead/ notorious problem solver
and mighty fighter of tech debt • Londoner • ❤ traveling and reading. Cooking better than 90% of the restaurants that provide take away https://frontendgirl.com/ -
Morning Routine Planner Time needed: 45 min drink coffee yoga
brush teeth cook breakfast -
Testing describe('total time is equal', () => { it('40 min
when yoga is selected', () => { ... }); it('15 min when drink coffee is selected', () => { ... }); it('5 min when brush teeth is selected', () => { ... }); it('20 min when cook breakfast is selected', () => { ... }); }); -
Morning Routine Planner Time needed: 45 min drink coffee yoga
brush teeth cook breakfast -
Morning Routine Planner true, false true, false true, false true,
false Possible Values -
Morning Routine Planner All possible variations [[true, true, true, true],
[true, true, true, false], [true, true, false, true], [true, true, false, false], [true, false, true, true], [true, false, true, false], [true, false, false, true], [true, false, false, false], [false, true, true, true], [false, true, true, false], [false, true, false, true], [false, true, false, false], [false, false, true, true], [false, false, true, false], [false, false, false, true], [false, false, false, false]]; -
Cartesian Product describe('total time is equal', () => { cartesian(...new
Array(4).fill([true, false])).forEach( ([isYoga, isCoffee, areTeeth, isBreakfast]) => { it('...', () => { ... }); }); }); -
Best explanation found with Google help “Property based testing is
a technique widely used in the Haskell community. The idea consists in automatically generating inputs for testing a function.” -
Flux Reducer const reducer = (state = initialState, action) =>
{ switch action.type { case 'ACTION_1': { ... return state1; } case 'ACTION_2': { ... return state2; } default: { return state; } } } -
Unit tests for flux reducer describe('reducer', () => { it('will
change state to state 1 on action 1', () => { expect(reducer(initialState, { type: 'ACTION_1', payload: payload1 })).toEqual(state1); }); it('will change state to state 2 on action 2', () => { expect(reducer(initialState, { type: 'ACTION_2', payload: payload2 })).toEqual(state2); }); }); -
Unit tests for flux reducer describe('reducer', () => { it('will
change state to state 1 on action 1', () => { expect(reducer(initialState, { type: 'ACTION_1', payload: payload1 })).toEqual(state1); }); it('will change state to state 2 on action 2', () => { expect(reducer(initialState, { type: 'ACTION_2', payload: payload2 })).toEqual(state2); }); }); -
Flux Reducer const reducer = (state = initialState, action) =>
{ switch action.type { case 'ACTION_1': { ... return state1; } case 'ACTION_2': { ... return state2; } default: { return state; } } } -
Flux Reducer with annotations type State = { isOnSale: boolean,
size: 'XS' | 'S' | 'M' | 'L' | 'XL', price: number } const reducer = (state: State = initialState, action: Action) => { switch action.type { case 'ACTION_1': { ... return state1; } case 'ACTION_2': { ... return state2; } default: { return state; } } } -
Flux Reducer with annotations type State = { isOnSale: boolean,
size: 'XS' | 'S' | 'M' | 'L' | 'XL', price: number } const reducer = (state: State = initialState, action: Action) => { switch action.type { case 'ACTION_1': { ... return state1; } case 'ACTION_2': { ... return state2; } default: { return state; } } } -
State type type State = { isOnSale: boolean, size: 'XS'
| 'S' | 'M' | 'L' | 'XL', price: number } -
State type const possibleValues = { isOnSale: [true, false], size:
['XS', 'S', 'M', 'L', 'XL'], price: [number1, number2, number3] } -
Testing describe('reducer', () => { it('will change state to state
1 on action 1', () => { cartesian([true, false], ['XS', 'S', 'M', 'L', 'XL'], [number1, number2, number3] ).map((isOnSale, size, price) => ({ isOnSale, size, price })).forEach(stateSample => { expect(reducer(stateSample, { type: 'ACTION_1', payload: payload1 })).toEqual(state1); }) }); }); -
Unit tests template generation ? type State = { isOnSale:
boolean, size: 'XS' | 'S' | 'M' | 'L' | 'XL', price: number } parsing -
Unit tests template generation ? describe('reducer', () => { it('will
change state to state 1 on action 1', () => { cartesian([true, false], ['XS', 'S', 'M', 'L', 'XL'], [number1, number2, number3] ).map((isOnSale, size, price) => ({ isOnSale, size, price })).forEach(stateSample => { ... }); }); }); generation