Testing Fundamentals
Avoiding Implementation Details
Example: SimpleMultiply
Requirement:
Create a function that can multiply 2 non zero integers. Negative numbers are out of scope
Assume JS still does not have the * operator
export const sum = (a, b) => a + b;
export const simpleMultiply = (a, b) => {
let total = 0;
for(let x = 0; x < a; x++) {
total = sum(total, b);
}
return total;
}
import {sum, simpleMultiply} from "./simpleMultiply";
jest.mock(add);
describe("multiply", () => {
// THIS PASSES
it("should call add 4 times when supplied with 3 & 4", () => {
multiply(3, 4);
expect(add).toBeCalledTimes(4);
});
// THIS PASSES
it("should call add 5 times when supplied with 3 & 5", () => {
multiply(3, 5);
expect(add).toBeCalledTimes(5);
});
});
Assume * is finally available
export const sum = (a, b) => a + b;
export const simpleMultiply = (a, b) => {
// let total = 0;
// for(let x = 0; x < a; x++) {
// total = sum(total, b);
// }
// return total;
return a * b
}
import {sum, simpleMultiply} from "./simpleMultiply";
jest.mock(add);
describe("multiply", () => {
// THIS FAILS
it("should call add 4 times when supplied with 3 & 4", () => {
multiply(3, 4);
expect(add).toBeCalledTimes(4);
});
// THIS FAILS
it("should call add 5 times when supplied with 3 & 5", () => {
multiply(3, 5);
expect(add).toBeCalledTimes(5);
});
});
import {simpleMultiply} from "./simpleMultiply";
jest.mock(add);
describe("multiply", () => {
// THIS WORKS AGAIN
it("should return 12 when 3,4 are passed in", () => {
expect(multiply(3, 4)).toBe(12);
});
// THIS WORKS AGAIN
it("should return 15 times when supplied with 3 & 5", () => {
expect(multiply(3, 5)).toBe(15);
});
});
Was there an advantage to the first test?
Test Validity Matrix
Having no test is better than having a false negative or false positive test
Why Can A Test Fail
-
Regression: Bug in source code that should be fixed
-
Change Request: Tests are irrelevant to new functionality. Decide whether to update/delete them.
- Refactoring: Tests have been incorrectly written to begin with. This implies you never actually had a valid test 😩😭🤕
Let's Write A Test For the Following Reducer
export const initialState = {
todos: [];
completed: [];
}
const todoReducer = (state = initialState, action) => {
switch(action.type) {
case "TODO_ADDED": {
const todo = action.payload;
return {
...state,
todos: [...state.todos, todo ],
}
}
default:
return state;
}
}
import reducer, { initialState } from "./reducer";
describe(() => {
it("returns the correct initial state", () => {
expect(reducer(undefined, {})).toEqual(initialState);
});
});
export const initialState = {
todos: "pooooooooooooooop";
completed: [];
}
const todoReducer = (state = initialState, action) => {
switch(action.type) {
case "TODO_ADDED": {
const todo = action.payload;
return {
...state,
todos: [...state.todos, todo ],
}
}
default:
return state;
}
}
const todoReducer = (state = initialState, action) => {
switch(action.type) {
case "TODO_ADDED": {
const todo = action.payload;
return {
...state,
todos: [...state.todos, todo ],
}
}
default:
return {
todos: [];
completed: [];
};
}
}
import reducer, { initialState } from "./reducer";
describe(() => {
it("returns the correct initial state", () => {
expect(reducer(undefined, {})).toEqual({
todos: [];
completed: [];
});
});
});
Black Box Testing Philosophy
Function, module, or class
input
output
Environment
side effect
Black Box Testing Philosophy
multiply
(2,3)
6
Environment
How Does A Component Fit the Black Box Model?
React Test Example
const AnimalPreview = (props) => (
<MuiCard>
<MuiCardImage src={prop.imageSource} variant={1} />
<MuiCardTitle>{prop.name}</MuiCardTitle>
<MuiCardText>{prop.summary}</MuiCardText>
<MuiCardActions>
<MuiButton onClick={prop.onShareClick}>Share</MuiButton>
<MuiButton onLearMoreClick={prop.onLearnMoreClick}>
Learn More
</MuiButton>
</MuiCardActions>
</MuiCard>
);
AnimalPreview
MuiCard
MuiCardTitle
h1
MuiCardText
p
MuiCardImage
img
MuiCardActin
button
Button
Button
button
AnimalPreview
h1
p
img
button
button
Copy of deck
By Yazan Alaboudi
Copy of deck
- 1,118