Skip to content

Commit a4ef05c

Browse files
committed
Updated README.md
1 parent 6375aaf commit a4ef05c

File tree

3 files changed

+57
-51
lines changed

3 files changed

+57
-51
lines changed

README.md

Lines changed: 36 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -44,77 +44,68 @@ to get a call at 3:00 AM to fix a bug that has crashed my app!
4444

4545
## Guiding principles for writing tests
4646

47+
The principles listed in this section are based on an article by Kent C. Dodds
48+
titled
49+
[Write tests. Not too many. Mostly integration.](https://kentcdodds.com/blog/write-tests).
50+
Kent is a testing guru with very good guidance on how to test. I have listed
51+
several more of his useful articles in the references below. So without further
52+
ado, let's jump in.
53+
4754
### Don't test implementation details
4855

49-
If your test does something that the consumer of your code doesn't, chances are
50-
that you are testing implementation details. For example, you may be exposing a
51-
private function just to test your component. This is a code smell, don't do
52-
it - a refactor can easily break your tests. Steer away from testing tools that
53-
allow you to test implementation details (e.g. Enzyme). Instead, use tools such
54-
as React Testing Library which make it very difficult to include implementation
55-
details in your tests. For more details, refer to
56-
[Write tests. Not too many. Mostly integration.](https://kentcdodds.com/blog/write-tests)
57-
by Kent C. Dodds.
56+
If your test does something that your user doesn't, chances are that you are
57+
testing implementation details. For example, you may be exposing a private
58+
function just to test your component. This is a code smell, don't do it - a
59+
refactor can easily break your test. Steer away from testing tools that allow
60+
you to test implementation details (e.g. Enzyme). Instead, use tools such as
61+
React Testing Library that make it difficult to include implementation details
62+
in your tests. For more details, refer to
5863

5964
### Test your components as a user would
6065

61-
The traditional testing wisdom was to write a lot of unit tests to test
62-
individual "units". We used to isolate our components from their environment
63-
using mocks. This approach still makes sense to test pure functions where the
64-
output is strictly based on its input. However, for front-end components which
65-
depend on communicating with their surrounding components, mocking reduces our
66-
confidence in the integrations. The latest thinking is to test several units
67-
together to recreate real interaction scenarios, hence the name _integration
68-
testing_.
66+
The classic testing wisdom was to write a lot of unit tests to test individual
67+
"units" of code. We used to isolate our components from their environment using
68+
mocks. This approach still makes sense for pure functions, but for front-end
69+
components, which depend on communications with surrounding components, mocking
70+
reduces our confidence in their integrations. So the latest thinking is to test
71+
several units together to recreate real interaction scenarios, hence the name
72+
_integration testing_.
6973

7074
This brings us to the guiding principle which is the foundation of the React
7175
Testing Library:
7276

7377
> The more your tests resemble the way your software is used, the more
7478
> confidence they can give you.
7579
76-
This translates to writing more "integration" style tests where, for example,
77-
you may want to drop a couple of components under a `<Context.Provider>` to test
78-
real user interactions. Or you may use [Mock Service Worker](https://mswjs.io/)
79-
to mock APIs at the network level rather than mocking at the component or
80+
This translates to writing more _integration_ style tests where, for example,
81+
you drop a couple of components under a `<Context.Provider>` to test real user
82+
interactions. Or you may use [Mock Service Worker](https://mswjs.io/) to mock
83+
APIs at the network level rather than excessively mocking at the component or
8084
service layer.
8185

8286
### Don't be obsessed with code coverage
8387

8488
There is a tradeoff between time spent writing tests and code coverage. Some
85-
organizations put undue focus on code coverage. Unfortunately this set the wrong
86-
goal for developers because after a certain point, the returns are not worth the
89+
organizations put undue focus on code coverage. Unfortunately this sets the
90+
wrong goal for developers - after a certain point, the returns are not worth the
8791
effort. You start seeing developers gaming the system by writing meaningless
88-
tests. Instead, the focus should be on _use case coverage_. Think of all the use
89-
cases (including corner cases) that you want to test to feel confident about
90-
your code. This approach will automatically yield high code coverage.
92+
tests. Instead, focus on _use case coverage_. Think of all the use cases
93+
(including corner cases) that you want to test to feel confident about your
94+
code. This approach will automatically yield high code coverage.
9195

92-
### Push business logic into pure functions vs. UI components
96+
### Push business logic into pure functions instead of UI components
9397

9498
For example, a Shopping Cart UI component should not compute the cart total.
9599
This should be pushed to a
96100
[pure function](https://en.wikipedia.org/wiki/Pure_function) because it is
97-
easier to test. See [here](./src/models/Cart.ts) for examples for pure functions
98-
and [related tests](./src/models/Cart.test.ts).
99-
100-
### Snapshot testing vs. traditional unit testing
101-
102-
Use snapshot tests only for small focused components where the snapshots can be
103-
easily read and verified for correctness (usually 20-30 lines max). For larger
104-
snapshots, developers tend to be undisciplined about reviewing them before
105-
committing, resulting in buggy code to be committed. Moreover, good tests encode
106-
the developer's intention. Snapshot tests lack the expression of this intent. So
107-
for anything beyond the simplest of components, prefer a traditional unit test.
108-
109-
Note: If you need to write a snapshot test, I recommend using
110-
react-testing-library because it generates cleaner snapshots. The other popular
111-
way of generating snapshots is react-test-renderer, but its output contains
112-
component properties and other details that are not relevant. Here's an
113-
[example of a snapshot test](./src/pages/NotFoundPage/NotFoundPage.test.tsx)
114-
using react-testing-library.
101+
easier to test. Even better, push it off to the back-end where more
102+
sophisticated calculations can be performed without affecting the UI. See
103+
[here](./src/models/Cart.ts) for examples for pure functions and
104+
[related tests](./src/models/Cart.test.ts).
115105

116106
## Techniques
117107

108+
- [Snapshot testing vs. traditional unit testing](./docs/snapshot-testing-vs-traditional-unit-testing.md)
118109
- [Difference between queryBy, getBy and findBy queries](./docs/difference-between-query-types.md)
119110
- Checking for existence of an element
120111
- Waiting for removal of an element

cypress/integration/checkout.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
const address = {
2-
"firstName": "John",
3-
"lastName": "Smith",
4-
"address": "100 Federal Street",
5-
"city": "Boston",
6-
"state": "MA",
7-
"zip": "02110"
2+
firstName: 'John',
3+
lastName: 'Smith',
4+
address: '100 Federal Street',
5+
city: 'Boston',
6+
state: 'MA',
7+
zip: '02110',
88
};
99

1010
describe('Checkout workflow', function () {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Snapshot testing vs. traditional unit testing
2+
3+
Use snapshot tests only for small focused components where the snapshots can be
4+
easily read by human beings and verified for correctness (usually 20-30 lines
5+
max). Developers tend to be undisciplined about reviewing larger snapshots,
6+
resulting in buggy code to be committed. Moreover, good tests encode the
7+
developer's intention. Snapshot tests lack the expression of this intent. So for
8+
anything beyond the simplest of components, prefer a traditional unit test.
9+
10+
If you do decide to write a snapshot test, use React Testing Library's APIs
11+
because they generate cleaner snapshots. The other popular way to generate
12+
snapshots is react-test-renderer, but its output contains component properties
13+
and other details that are not relevant. Here's an
14+
[example of a snapshot test](../src/pages/NotFoundPage/NotFoundPage.test.tsx)
15+
using React Testing Library.

0 commit comments

Comments
 (0)