- why?
- how?
- what? comes from experience and the system we're testing and even the tech stack.
- when? test-first vs test after.
Confidence (in the sense of trusting your code). Verifying correctess.
We write code to test our code.
Why learn it?
- good for resume.
- can work on QA and DevOps.
- helps understand how an application works.
- prevents regressions.
- safety net.
Tooling: Test runner (Mocha) + assertion library (Chai).
We are using Jest.
What could happen if I have no tests.
- test manually, as the app grows, the time needed will not scale.
- regressions, code that used to work breaks.
- you just don't know if the code is correct for all cases.
- adding new features becomes slow.
Types
- unit tests. Fastest.
- integration tests.
- end to end. Slow.
- component testing. (for component based frameworks, like React, Angular, Vue, etc.)
- snapshot testing. (unique to our stack/tools)
- coverage test.
- functional testing.
- performance testing.
- aceptance test.
We'll concentrate on:
- unit
- component
- snapshot
- instead of running the tests manually use watch mode.
- tests run automatically as files change.
- only tests pertaining to changed files run.
- Jest detects changes automatically.
- change the npm test script to:
jest --watch
. - changing the code or the tests will re-run the tests.
- using
ctrl + c
will stop the test runner/watcher.
Some commonly used (and useful) matchers.
to be or not to be, that is the question.
- Not: reverses the assertion.
- toBe: that two values are equivalent using strict equality (checks reference/identity).
- toEqual: that two values are equivalent by looking at the values (if walks like a duck, it's a duck). For two different arrays with the same values, toBe fails and toEqual succeeds.
- toContain: checks that a value exists in an array.
- toHaveLength: checks the lenght of an array. Like toContain, it is more readable than using toEqual and toBe combined with array methods.
- can we install Jest globally?
- can Jest tests be run as part of the build and deployment processes?
- characteristics of unit tests
- fast.
- simple to write and execute.
- used to test correctness.
- written by developers.
- the tool for doing TDD/BDD.
- why is
watch mode
convenient? how can we "turn it on" when running our tests?
- drawbacks of testing.
- more about Jest.
- the other way to have Jest run tests (colocated ending in
.spec.js
or.test.js
). - the other types of tests (component and snapshot).
- setup and teardown globals.
- skipping and isolating tests.
- testing asynchronous operations.
- fakes, stubs, and mock functions aka spies.
- more code to write, and maintain.
- more tooling.
- additional dependencies.
- may provide a false sense of security.
- trivial test failures may break the build.
- a test runner + cli in npm package.
- made by Facebook and included out of the box with create-react-app.
- general purpose, but works very well with React applications.
- recommended by the React team.
- can:
- run tests (mocha too)
- asynchronous code testing (mocha too).
- spies included.
- snapshot testing.
- module mocking.
- includes coverage reports
- any file inside a
__tests__
folder will be run automatically. - any file that ends in
.spec.js
or.test.js
will also be executed automatically.
- appearance and functionality of a component.
- highly sensitive to small changes.
- great against regression.
- verifies changes to component output resulting from changes to state.
- does not verify interaction between components.
- sub-type of component testing.
- very useful to spot regressions.
- automatically generated by Jest.
- a snapshot is a JSON based record of a component's output.
- snapshots are saved to a
__snapshots__
folder as a sibling of the tested component. - the snapshots are commited to source control.
- during testing, the components are automatically compared to their last recorded snapshot.
- checks current output against prior output.
- fails with any change to the component.
- first, install
react-test-renderer
if you haven't. - second
import renderer from 'react-test-renderer';
. - then
import { TheComponent } from './TheComponent';
. - create a tree.
- run the assertion to match snapshot.
import renderer from 'react-test-renderer';
import { TheComponent } from './TheComponent';
const tree = renderer.create(<TheComponent />);
expect(tree.toJSON()).toMatchSnapshot();
- the first time, the snapshot is created.
- when the snapshot fails, the developer can decide to update the snapshot if the change was intended.
- to update snapshot:
jest TheComponent -u
or--update
(if you used create-react-app the command isyarn test -u
), but, ain't nobody got time for that.
-
fast and semi-automatic.
-
catches regressions that could be missed by humans.
-
works with any library that generates HTML components (Angular, Vue, React).
-
better than no tests at all to protect applications from regressions.
-
easy to override, save new snapshot.
-
protects only against regression.
-
easy to break, smallest change will fail test suite.
-
adds more files to the repository.
-
waste of time to have them while actively making changes to components.
- exist in the global scope like
describe
andit
. - beforeAll: runs once before the first test.
- beforeEach: runs before the tests, good for setup code. // test runs
- afterEach: runs after the tests, good for clean up.
- afterAll: runs once after the last test.
- skipping tests:
it.skip()
- isolating is used to pick the tests you want to run:
it.only()
- it also works at the test suite level:
describe.only()
ordescribe.skip()
- does not complete right away.
- Jest must be notified that the test completed.
- techiques:
- invoke a
done()
callback that is passed to the test. - return a promise from a test.
- pass an
async
function todescribe
. Preferred and cleanest syntax.
- invoke a
-
a duplicate of a unit of code that has no implementation.
-
has the same API (method names, return value type and shape must be returned) of the original unit, but has no side effects.
-
prevent side effects.
-
reduce dependencies.
-
isolate tests to simplify testing.
-
add mocks to a
__mocks__
folder, next to the mocked module. -
to mock npm modules, just name your mock the same as the module and it will be loaded automatically.
- folder must be at the root of the application, next to
node_modules
folder. - add a file inside the folder with the name of the module you want to mock.
- folder must be at the root of the application, next to
-
to mock local files:
- add the
__mocks__
folder at the same level of the file to mock. - where the mock is needed (inside the test file) call
jest.mock('path to code file to be mocked');
.
- add the
Spies are functions that provide information about how they are used.
-
counts function calls.
-
records arguments passed to it when it is called.
-
we can return fake values in order to test specific scenarios.
-
to create
spies
:const jamesBond = jest.fn()
;. This creates anoop
function. -
passing a funcion as the first argument, wraps that function into a
spy
that then keeps track of useful information.