Skip to content

Commit 875c133

Browse files
committed
Testing philosophy, properties of a good test.
1 parent c1239d1 commit 875c133

File tree

3 files changed

+131
-2
lines changed

3 files changed

+131
-2
lines changed

module5-testing/r1-what-is-a-test/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,7 @@ run it before sending a PR or while working on the test. In a process called
1616
pull request is proposed. This means that generally, if your code and pull
1717
request are not passing the tests, it cannot be merged in.
1818

19-
Suppose you had a function called `square(n)`, that is supposed to square a
20-
number.
19+
There are many types of tests: unit tests, integration tests, screenshot tests,
20+
and so on. In a later section, we will talk about some of these types of tests.
21+
Most commonly, we will refer to unit tests, which are the most frequent type of
22+
tests.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Testing Philosophy
2+
In this section, we'll discuss some aspects of testing philosophy. There are
3+
many different ways to approach testing.
4+
5+
In real life, you may perhaps work at
6+
companies that do almost no testing (this is not good, but it is the reality).
7+
This is especially true in smaller companies. You may work at a company that
8+
chooses only to test certain components or write certain types of tests.
9+
Finally, as mentioned previously, at some companies, especially bigger ones, you
10+
may be required to write tests so that every line of code is covered by a test.
11+
12+
Simply writing a test is not sufficient: there are also good and bad ways to
13+
write tests. In the sections ahead, we'll consider some additional factors about
14+
the testing process and the quality of tests.
15+
16+
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Properties of a good test
2+
As mentioned previously, simply writing a test is not the same as writing a good
3+
test. In this section, we'll examine some properties of what makes a good test.
4+
5+
## Size: Focused tests
6+
A well-written test should not test too many things at once. In general, test
7+
cases should be well-isolated and have a [single
8+
responsibility](https://en.wikipedia.org/wiki/Single-responsibility_principle)
9+
or intention.
10+
11+
Consider the previous example of the `absolute()` function. Suppose the test
12+
instead looked like this:
13+
14+
```javascript
15+
describe('absolute', () => {
16+
it('should correctly handle inputs', () => {
17+
const result1 = absolute(1);
18+
expect(result0).toBe(1);
19+
const result1 = absolute(-1);
20+
expect(result1).toBe(1);
21+
const result2 = absolute(0);
22+
expect(result2).toBe(0);
23+
});
24+
});
25+
```
26+
27+
Now compare this to the original. Which one do you find more readable and
28+
organized? While this is a simple example, separating the cases for clarity
29+
becomes especially important with more complex functions.
30+
31+
```javascript
32+
describe('absolute', () => {
33+
it('should return positive number if input positive', () => {
34+
const result = absolute(1);
35+
expect(result).toBe(1);
36+
});
37+
it('should return positive number if input negative', () => {
38+
const result = absolute(-1);
39+
expect(result).toBe(1);
40+
});
41+
it('should return zero if input is zero', () => {
42+
const result = absolute(0);
43+
expect(result).toBe(0);
44+
});
45+
});
46+
```
47+
48+
## Redundancy: avoid overlapping test cases
49+
As a related topic, you usually want to avoid test cases that overlap too much
50+
with existing test cases. For example, consider the following test case for the
51+
above. Is it useful, or is it redundant, overlapping with one of the test cases
52+
above?
53+
54+
```javascript
55+
it('should return positive number if input is large and negative', () => {
56+
const result = absolute(-100);
57+
expect(result).toBe(100);
58+
});
59+
```
60+
61+
This case is redundant. Testing `absolute(-1)` and `absolute(-100)` is not very
62+
useful; the two test cases overlap. We want to avoid this.
63+
64+
It is often asked how much overlap is okay. Inevitably, some test cases will
65+
overlap with each other. There is no correct answer here: just know that some
66+
overlap is okay, but you want to do your best to avoid redundancy by selecting
67+
test cases that are representative of the cases of your function.
68+
69+
In the
70+
programmer's mindset, usually there are a set of possible scenarios to consider.
71+
For example, in the case of the `absolute()` function, there are three distinct
72+
scenarios that define the behavior: positive, negative, and zero. Whether the
73+
negative number is large or not makes no difference.
74+
75+
## Thoroughness
76+
In this module, it was mentioned several times that good test coverage means
77+
that, if the code is behaving incorrectly, even in one line or in one
78+
if-condition, some line will fail.
79+
80+
A common problem with tests is that some case is missing. Perhaps when certain
81+
arguments are passed to your function, it behaves differently. A good suite of
82+
tests will make sure to cover these cases.
83+
84+
## Organization: Arrange-Act-Assert
85+
Tests generally follow approximately the same pattern, and this has been
86+
crystallized in a commonly adopted idea called ["Arrange Act
87+
Assert."](https://automationpanda.com/2020/07/07/arrange-act-assert-a-pattern-for-writing-good-tests/)
88+
89+
1. **Arrange**: Many tests require some type of setup; the setup should come
90+
initially.
91+
2. **Act**: In the act step, the actual behavior being tested should be invoked,
92+
such as a function call, an API call, a component render, etc.
93+
3. **Assert**: Finally, to ensure correctness, assert the expected outcomes.
94+
This was seen earlier using the `expect` function. Expect and assert, in this
95+
context, are synonymous.
96+
97+
## Additional readings
98+
This [StackOverflow
99+
question](https://stackoverflow.com/questions/61400/what-makes-a-good-unit-test)
100+
gives some interesting insights into what are considered good properties of a
101+
unit test.
102+
103+
Google has a good resource called *Testing on the Toilet*. On the back of the
104+
door in every toilet stall at Google, you can find a one-page flyer that
105+
describes some aspect of testing (that's how important testing is!). These are
106+
publicized. Some good ones for junior developers are included below:
107+
108+
- [Keep tests focused](https://testing.googleblog.com/2018/06/testing-on-toilet-keep-tests-focused.html)
109+
- [DAMP](https://www.googblogs.com/testing-on-the-toilet-tests-too-dry-make-them-damp/). Don't overuse functions in test code, focus on readability.
110+
- [Just say no to end-to-end tests](https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html). Avoid overusing tests that connect too many parts of your system.
111+

0 commit comments

Comments
 (0)