Skip to content

Commit 5368538

Browse files
committed
Update testing.md
1 parent a25c649 commit 5368538

File tree

1 file changed

+79
-73
lines changed

1 file changed

+79
-73
lines changed

developer_docs/testing.md

Lines changed: 79 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,9 @@ Find more commands in the [Jest documentation](https://jestjs.io/docs/cli).
5858
## Why write tests
5959
- Good place to start if you're learning the codebase because it's harder to mess up production code
6060
- Benefits all future contributors by allowing them to check their changes for errors
61-
- Catches easy-to-miss errors
61+
- Increased usage: Most code with only ever have a single invocation point, but this means that code might not be particularly robust and lead to bugs if a different devleoper reuses it in a different context. Writing tests increases the usage of the code in question and may improve the long-term durability, along with leading developers to refactor their code to be more usable. [[3]](#References)
6262
- Lets you check your own work and feel more comfortable sumbitting PRs
63+
- Catches easy-to-miss errors
6364
- Good practice for large projects
6465
- Many of the existing components don't have tests yet, and you could write one :-)
6566

@@ -71,30 +72,62 @@ When you modify an existing component, it's a good idea to run the test suite to
7172

7273
## Writing a test
7374
Want to get started writing a test for a new file or an existing file, but not sure how?
75+
76+
7477
### For React components
75-
(the below assumes we're using proposed folder structure 1)
76-
1. Make a new file in the ``__tests__`` folder that's directly adjacent to your file. For example, if ``example.jsx`` is in ``src/components``, then you would make a file called ``example.test.jsx`` in ``src/components/__tests__``
78+
1. Make a new file directly adjacent to your file. For example, if ``example.jsx`` is ``src/components/example.jsx``, then you would make a file called ``example.test.jsx`` at ``src/components/example.test.jsx``
7779
2. Check if the component is connected to redux or not.
7880
3. If it is, see the [redux section](#Testing-Redux) below on how to write tests for that.
7981
4. If it's not, see the [section below on writing tests for unconnected components](#Testing-plain-components).
80-
5. If you're testing UI elements, there are many ways of querying for them, but you can add a data-testid attribute to the component in the source code and use ``getByTestId("testid")`` to retrieve it.
8182
)
83+
5. "Arange, Act, Assert:" In other words, *arrange* the set up for the test, *act* out whatever the subject's supposed to do, and *assert* on the results. [[3]](#References)
84+
85+
### In every test file
86+
Maybe we want to add these as comments??
87+
- What behavior is and isn't covered by the suites What dependencies should be replaced with mocks and what should be left realistic
88+
- The primary design benefit (if any) of these tests
89+
- The primary regression protection (if any) provided by these tests
90+
- What an example test should look like
91+
- The maximum permissible elapsed time for a run of an individual test or for the full suit
92+
93+
### Consistency across tests
94+
> "Teams that adopt a rigid and consistent structure to each test tend to more readily understand each test, because every deviation from the norm can be trusted to be meaningful and somehow specific to the nature of the subject."
95+
- We want to default to using meaningless test data stored in the redux-test-stores folder.
96+
- Be sure to follow the folder structure
97+
- Follow the rendering guidelines set up for the components in this README.
98+
99+
### Querying for elements
100+
Read about the recommended order of priority for queries in [the testing library docs](https://testing-library.com/docs/guide-which-query/#priority). We recommend using roles and text, or labels. You can use this [handy extension](https://chrome.google.com/webstore/detail/testing-playground/hejbmebodbijjdhflfknehhcgaklhano/related) to do this.
101+
82102

83103
### What to test
84104
For any type of component, you might want to consider testing:
85-
- User input results in the class's method being called.
86-
```js
87-
//component is the return value of calling render()
88-
const spy1 = jest.spyOn(component.instance(), 'func1');
89-
act(() => {
90-
fireEvent.click(screen.getByTestId("testid"));
91-
});
92-
expect(spy1).toHaveBeenCalledTimes(1);
93-
```
94-
- The text or divs that you expect to be on the page are actually there.
105+
- The text or divs that you expect to be on the page are actually there. You can use [Queries](https://testing-library.com/docs/queries/about/) for this.
95106
- a previously saved snapshot of the HTML matches a snapshot taken during testing.
96107
- what else?? help!
97108

109+
>Only test the behaviors you know you need to care about. For example, if the desired behavior of a particular edge case doesn't truly matter yet or isn't fully understood, don't write a test for it yet. Doing so would restrict the freedom to refactor the implementation. Additionally, it will send the signal to future readers that this behavior is actually critical, when it very well might not be (perhaps a form of [accidental creativity]()). [[3]](#References)
110+
111+
**Don't test unreachable edge cases:** You would have to add code to your original implementation to guard against these cases. The future proofing and the added cost to the codebase "is generally not worth their preceived potential benefits" [[3]](#References)
112+
113+
**Make sure your tests are sufficient:** You want to make sure your test actually specifies all the behaviors you want to ensure the code exhibits. For example, testing that ``1+1 > 0`` would be correct, but insufficient. [[3]](#References)
114+
115+
### File structure
116+
Each test should have a top-level ```describe`` block to group related blocks together, with the name of the component under test.
117+
*example.test.ts*
118+
119+
```js
120+
import example from './example';
121+
122+
describe('example', () => {
123+
it('creates a new example', () => {
124+
//your tests here
125+
});
126+
});
127+
128+
```
129+
130+
98131
### For Redux action creators or reducers
99132
See the [redux section](#Testing-Redux) below :)
100133

@@ -116,58 +149,8 @@ You can also see it used in the context of a test [in the SketchList.test.jsx fi
116149

117150
## Files to be aware of
118151

119-
### Proposed folder structure 1
120-
All tests in ``__tests__`` folders that are directly adjacent to the files that they are testing. For example, if you're testing ``examplefolder/Sketchlist.test.jsx``, the test would be in ``examplefolder/__tests__/Sketchlist.test.jsx``. This is so that the tests are close to the files they're testing but are still hidden away from view most of the time. This also means that any snapshot files will be stored in the testing folder, such as ``examplefolder/__tests__/__snapshots__/Sketchlist.test.jsx.snap``
121-
122-
Manual mocks are in ``__mocks__`` folders are adjacent to the modules that they're mocking.
123-
124-
Note: Even if you mock a user module in a ``__mocks__`` folder, user modules have to be explictly mocked in the test too, with ``Jest.mock("path_to_module")``
125-
126-
Node modules are mocked in the ``__mocks__`` folder at the root of the client folder, which also includes any mocks that are needed for user modules at the root of the folder directory.
127-
128-
```
129-
.
130-
└── client
131-
├── __mocks__
132-
│ ├── axios.js
133-
| ├── i18n.js
134-
| └── ...other Node modules you want to mock
135-
├── modules
136-
│ ├── IDE
137-
│ │ ├── actions
138-
│ │ │ ├── __mocks__
139-
│ │ │ │ ├── projects.js
140-
│ │ │ │ └─ ... other action creator mocks
141-
│ │ │ ├── __tests__
142-
│ │ │ │ ├── projects.test.js
143-
│ │ │ │ └─ ... other redux action creator tests
144-
│ │ │ └── ... action creators
145-
│ │ ├── components
146-
│ │ │ ├── __tests__
147-
│ │ │ │ ├── __snapshots__
148-
│ │ │ │ │ ├── SketchList.test.jsx.snap
149-
│ │ │ │ │ └─ ... other snapshots
150-
│ │ │ │ ├── SketchList.test.jsx
151-
│ │ │ ├── SketchList.test.jsx
152-
│ │ │ └── ... and more component files
153-
│ │ ├── reducers
154-
│ │ │ ├── __tests__
155-
│ │ │ │ ├── assets.test.js
156-
│ │ │ │ └─ ... other reducer tests
157-
│ │ │ ├── assets.js
158-
│ │ │ └── ...more reducers
159-
│ └── ... more folders
160-
├── redux_test_stores
161-
| ├── test_store.js
162-
│ └── ...any other redux states you want to test
163-
├── i18n-test.js
164-
├── jest.setup.js
165-
├── test-utils.js
166-
└──... other files and folders
167-
```
168-
169-
### Proposed folder structure 2
170-
All tests are directly adjacent to the files that they are testing. For example, if you're testing ``examplefolder/Sketchlist.test.jsx``, the test would be in ``examplefolder/Sketchlist.test.jsx``. This is so that the tests are as close as possible to the files. This also means that any snapshot files will be stored in the same folder, such as ``examplefolder/__snapshots__/Sketchlist.test.jsx.snap``
152+
### Folder structure
153+
All tests are directly adjacent to the files that they are testing, as described in the [React docs](https://reactjs.org/docs/faq-structure.html#grouping-by-file-type). For example, if you're testing ``examplefolder/Sketchlist.test.jsx``, the test would be in ``examplefolder/Sketchlist.test.jsx``. This is so that the tests are as close as possible to the files. This also means that any snapshot files will be stored in the same folder, such as ``examplefolder/__snapshots__/Sketchlist.test.jsx.snap``
171154

172155
Manual mocks are in ``__mocks__`` folders are adjacent to the modules that they're mocking.
173156
@@ -331,7 +314,7 @@ Consider what you want to test. Some possible things might be:
331314
- User input results in the expected function being called with the expected argument.
332315
```js
333316
act(() => {
334-
fireEvent.click(screen.getByTestId("testid"));
317+
fireEvent.click(screen.getByLabelText('Username'));
335318
});
336319
expect(yourMockFunction).toHaveBeenCalledTimes(1);
337320
expect(yourMockFunction.mock.calls[0][0]).toBe(argument);
@@ -446,29 +429,52 @@ A few components also import ``./client/i18n.js`` (or ``./client/utils/formatDat
446429
447430
## Some more background on tests
448431
449-
### test driven development (TDD)
450-
BDD???
432+
### Test Driven Development (TDD)
433+
Do we want a section here about TDD history?
451434
452435
### snapshot testing
453436
You can save a snapshot of what the HTML looks like when the component is rendered.
454437
455438
### integration tests
456-
Testing multiple components together. A small example is rendering a parent component and a child component within that.
439+
Testing multiple components together. A small example is rendering a parent component in order to test the interactions between children components. For frontend development, integration tests might focus on end-to-end flows using Puppeter or another type of headless browser testing. We don't do this just yet.
457440
458441
### unit tests
459-
Most of our tests are of this type. In this, you're testing a the functionality of a single component and no more.
442+
Most of our tests are of this type. In this, you're testing a the functionality of a single component and no more. They provide lots of feedback on the specific component that you're testing, with the cost of high [redundant coverage](https://github.com/testdouble/contributing-tests/wiki/Redundant-Coverage) and more time spent refactoring tests when components get rewritten.
443+
444+
### Other terminology for mocking
445+
Thanks [Test Double Wiki](https://github.com/testdouble/contributing-tests/wiki/Test-Double) for the definitions.
446+
#### Test double
447+
Broadest available term to describe any fake thing used in place of a real thing for a test.
448+
#### Stub
449+
Any test double that uses a preconfigured response, such always responding with placeholder json to a certain fetch call.
450+
#### Fake
451+
A test double that provides an alternate implementation of a real thing for the purpose of a test.
452+
#### Mock
453+
Colloquially can mean any of the above, just used generally for test doubles.
454+
#### Partial mock
455+
Refers to any actual object which has been wrapped or changed to provide artificial responses to
456+
some methods but not others. Partial mocks are widely considered to be an anti-pattern of test double usage.
457+
458+
#### Spy
459+
Records every invocation made against it and can verify certain interactions took place after the fact.
460460
461461
## Internationalization
462462
This project uses i18next for internationalization. If you import the render function with the i18n wrapper from ``test_utils.js``, it's set up to use English, so the components with be rendered with English text and you should be able to count on this to test for specific strings.
463463
464464
## Tips
465465
1. Make test fail at least once to make sure it was a meaningful test
466466
2. "If you or another developer change the component in a way that it changes its behaviour at least one test should fail." - [How to Unit Test in React](https://itnext.io/how-to-unit-test-in-react-72e911e2b8d)
467+
3. Avoid using numbers or data that seem "special" in your tests. For example, if you were checking the "age" variable in a component is a integer, but checked it as so ``expect(person.ageValidator(18)).toBe(true)``, the reader might assume that the number 18 had some significance to the function because it's a significant age. It would be better to have used 1234.
467468
468469
## More Resources
469-
- any other resources for learning about tests here?
470+
- [React Testing Library Cheatsheet](https://testing-library.com/docs/react-testing-library/cheatsheet/)
470471
471472
## References
472473
1. [Best practices for unit testing with a react redux approach](https://willowtreeapps.com/ideas/best-practices-for-unit-testing-with-a-react-redux-approach)
473474
474-
2. [How to test your react-redux application (this article also references axios)](https://medium.com/asos-techblog/how-to-test-your-react-redux-application-48d90481a253)
475+
2. [How to test your react-redux application (this article also references axios)](https://medium.com/asos-techblog/how-to-test-your-react-redux-application-48d90481a253)
476+
477+
3. [Testing Double Wiki (Special thanks to this wiki for being such a comprehensive guide to the history of testing and best practices.)](https://github.com/testdouble/contributing-tests/wiki/Tests%27-Influence-on-Design)
478+
479+
## Special thanks
480+
Thank you to HipsterBrown for helping us out with writing this documentation.

0 commit comments

Comments
 (0)