Skip to content

Commit 8af993d

Browse files
committed
add outside-in to testing principles
1 parent 0423bc6 commit 8af993d

File tree

1 file changed

+94
-5
lines changed

1 file changed

+94
-5
lines changed

docs/pages/principles/testing.md

Lines changed: 94 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,100 @@ parent: Principles
1010

1111
# Testing recommendations
1212

13-
## Outside-In Tests
14-
* live outside of source code, in the tests/ directory
15-
* Describe the various types of outsid-in tests (integration, fuzz, e2e, API)
16-
* Reference topical guides
17-
* Provide suggestions for testing categories
13+
## External or outside-in testing
14+
A good place to start writing tests is from the perspective of a user of your module
15+
or library, as described in the [Test Tutorial][], and [Testing with pytest guide][].
16+
These test cases live outside your code, and include many styles or types of test
17+
that you may have heard of (behavioral, fuzz, end-to-end, feature, etc., etc.).
18+
There are many, many kinds of tests that can be used to verify that your code is correct,
19+
and works as expected, and a lot to learn.
20+
21+
### Any test case, is better than none
22+
When in doubt, write the test that makes sense to you at the time. While you are learning,
23+
and writing your first test suites, try not to get bogged down in the taxonomy of test cases.
24+
As you write and use your test suite, the reason for classifying and sorting some types
25+
of tests into different test-suites will become apparent.
26+
27+
### As long as that test is correct...
28+
It can be surprisingly easy to write a test that passes when it should fail, especially
29+
when using complicated Mocks and fixtures. The best way to avoid this is to deliberately
30+
break the code you are testing, hard-code a failure, and run the test-case to make sure
31+
it fails when the code is broken.
32+
33+
* Check that your test fails when it should!
34+
* Keep It Simple: Excessive use of mocks and fixtures can make it difficult to know if our
35+
test is running the code we expect it to.
36+
* Test one thing at a time: A single test, should test a single behavior, and it is better
37+
to write many test cases for a single function or class, than one giant case.
38+
39+
40+
{: .highlight-title }
41+
> A note to new test developers:
42+
>
43+
> This is a good place to pause and go write some tests.
44+
> The rest of these principles apply to more advanced test development.
45+
> As you gain experience and your test suite(s) grow, taxonomy of test cases,
46+
> the and the use/need for different kinds of tests will become more clear.
47+
48+
49+
### Taxonomy of outside-in tests
50+
A non-exhaustive discussion of some common types of tests.
51+
52+
^_^ Dont Panic ^_^
53+
54+
Depending on your project, you may not need many, or most of these kinds of tests.
55+
* A library project probably does not need to test integration with microservices.
56+
* A library with no 3rd party dependencies, does not need test them.
57+
* Fuzz testing is for critical code, that many users rely on.
58+
59+
#### Behavioral, Feature, or Functional Tests:
60+
High-level tests, which ensure a specific feature works.
61+
Used for testing things like:
62+
* Loading a file
63+
* Setting a debug flag results in debug messages being printed
64+
* A configuration option, affects the behavior of the code as expected.
65+
66+
67+
#### Fuzz Tests
68+
Fuzz tests, attempt to test the full range of possible inputs to a function.
69+
They are good for finding edge-cases, where what should be valid input causes a failure.
70+
[Hypothesis](https://hypothesis.readthedocs.io/en/latest/) is an excellent tool for this,
71+
and a lot of fun to use.
72+
73+
* SLOW TESTS: fuzz tests can take a very long time to run,
74+
and should usually be placed in a test suite, which we run seperately from our faster tests.
75+
* Reserve fuzz testing for the few critical functions, where it really matters.
76+
77+
78+
#### Integration Tests
79+
The word "Integration" is a bit overloaded, and can reffer to many levels of integration between
80+
our code, its dependencies, and external systems.
81+
82+
##### Code level
83+
Test the integration between your software and external / 3rd party dependencies.
84+
Low-level testing of your code-base, where we run the code imported from dependencies,
85+
without mocking it.
86+
87+
##### Environment level
88+
Testing that your software works in the environments we plan to run it in.
89+
* Running inside of a docker container
90+
* Using GPU's or other specialized hardware
91+
* Deploying it to cloud servers
92+
93+
##### System level
94+
Testing that it interacts with other software in a larger system.
95+
* Interactions with other services, on local or cloud-based platforms.
96+
* micro-service, Database, or API connections and interactions.
97+
98+
99+
#### End to End Tests
100+
The slowest, and most brittle, of all tests. Here, we setup an entire production-like system,
101+
and run tests against it.
102+
* Create a Dev / Testing / staging environment, and run tests against it to make sure everything
103+
works together.
104+
* Fake user input, using tools like [Selenium](https://www.selenium.dev/documentation/)
105+
* Processing data from a pre-loaded test database.
106+
* Manual QA testing
18107

19108

20109
## Unit Tests

0 commit comments

Comments
 (0)