Skip to content

Commit bcb7119

Browse files
committed
Improve README a bit
1 parent 23aed77 commit bcb7119

1 file changed

Lines changed: 87 additions & 86 deletions

File tree

README.md

Lines changed: 87 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,51 @@ that allows tests to be written in arbitrary nested describe-blocks,
88
similar to RSpec (Ruby) and Jasmine (JavaScript).
99

1010
The main inspiration for this was
11-
a [video](https://www.youtube.com/watch?v=JJle8L8FRy0>) by Gary Bernhardt.
11+
a [video](https://www.youtube.com/watch?v=JJle8L8FRy0) by Gary Bernhardt.
12+
13+
## Why bother?
14+
15+
I've found that quite often my tests have one "dimension" more than my production
16+
code. The production code is organized into packages, modules, classes
17+
(sometimes), and functions. I like to organize my tests in the same way, but
18+
tests also have different *cases* for each function. This tends to end up with
19+
a set of tests for each module (or class), where each test has to name both a
20+
function and a *case*. For instance:
21+
22+
```python
23+
def test_my_function_with_default_arguments():
24+
def test_my_function_with_some_other_arguments():
25+
def test_my_function_throws_exception():
26+
def test_my_function_handles_exception():
27+
def test_some_other_function_returns_true():
28+
def test_some_other_function_returns_false():
29+
```
30+
31+
It's much nicer to do this:
32+
33+
```python
34+
def describe_my_function():
35+
def with_default_arguments():
36+
def with_some_other_arguments():
37+
def it_throws_exception():
38+
def it_handles_exception():
39+
40+
def describe_some_other_function():
41+
def it_returns_true():
42+
def it_returns_false():
43+
```
44+
45+
It has the additional advantage that you can have marks and fixtures that apply
46+
locally to each group of test functions.
47+
48+
With pytest, it's possible to organize tests in a similar way with classes.
49+
However, I think classes are awkward. I don't think the convention of using
50+
camel-case names for classes fit very well when testing functions in different
51+
cases. In addition, every test function must take a "self" argument that is
52+
never used.
53+
54+
The pytest-describe plugin allows organizing your tests in the nicer way shown
55+
above using describe-blocks.
1256

1357
## Installation
1458

@@ -112,8 +156,10 @@ describe_prefixes = ["custom_prefix_"]
112156
```
113157

114158
Functions prefixed with `_` in the describe-block are not collected as tests.
115-
This can be used to group helper functions. Otherwise, functions inside the
116-
describe-blocks need not follow any special naming convention.
159+
This can be used to group helper functions. Thanks to closures, a helper
160+
defined in an enclosing describe-block is visible in all nested blocks.
161+
Otherwise, functions inside the describe-blocks need not follow any special
162+
naming convention.
117163

118164
```python
119165
def describe_function():
@@ -126,7 +172,6 @@ def describe_function():
126172
...
127173
```
128174

129-
130175
## Fixtures as describe arguments
131176

132177
When several tests in a describe-block need the same fixture, you can pass
@@ -145,10 +190,10 @@ def user():
145190
def describe_create_book(user):
146191

147192
def with_valid_book(valid_book):
148-
# use the user and valid_book fixtures ...
193+
... # use the user and valid_book fixtures
149194

150195
def with_invalid_book(invalid_book):
151-
# use the user and invalid_book fixtures ...
196+
... # use the user and invalid_book fixtures
152197
```
153198

154199
This is functionally equivalent to declaring the fixture as an argument of
@@ -175,6 +220,42 @@ For the same reason, fixtures with a scope higher than `function` and
175220
autouse fixtures should not use describe arguments, because they may be
176221
set up before the values are injected.
177222

223+
## Shared behaviors
224+
225+
If you've used RSpec's shared examples or test class inheritance, then you may
226+
be familiar with the benefit of having the same tests apply to
227+
multiple "subjects" or "SUTs" (systems under test).
228+
229+
```python
230+
from pytest import fixture
231+
from pytest_describe import behaves_like
232+
233+
def a_duck():
234+
def it_quacks(sound):
235+
assert sound == "quack"
236+
237+
@behaves_like(a_duck)
238+
def describe_something_that_quacks():
239+
@fixture
240+
def sound():
241+
return "quack"
242+
243+
# the it_quacks test in this describe will pass
244+
245+
@behaves_like(a_duck)
246+
def describe_something_that_barks():
247+
@fixture
248+
def sound():
249+
return "bark"
250+
251+
# the it_quacks test in this describe will fail (as expected)
252+
```
253+
254+
Fixtures defined in the block that includes the shared behavior take precedence
255+
over fixtures defined in the shared behavior. This rule only applies to
256+
fixtures, not to other functions (nested describe blocks and tests). Instead,
257+
they are all collected as separate tests.
258+
178259
## Using docstrings as describe block names
179260

180261
By default, describe-blocks are reported under the name of their function,
@@ -210,86 +291,6 @@ test_wallet.py::a wallet::when it is empty::it_has_no_balance PASSED
210291
Note that the docstring-based names become part of the test node IDs, which
211292
are used when selecting tests with `-k` or by node ID on the command line.
212293

213-
## Why bother?
214-
215-
I've found that quite often my tests have one "dimension" more than my production
216-
code. The production code is organized into packages, modules, classes
217-
(sometimes), and functions. I like to organize my tests in the same way, but
218-
tests also have different *cases* for each function. This tends to end up with
219-
a set of tests for each module (or class), where each test has to name both a
220-
function and a *case*. For instance:
221-
222-
```python
223-
def test_my_function_with_default_arguments():
224-
def test_my_function_with_some_other_arguments():
225-
def test_my_function_throws_exception():
226-
def test_my_function_handles_exception():
227-
def test_some_other_function_returns_true():
228-
def test_some_other_function_returns_false():
229-
```
230-
231-
It's much nicer to do this:
232-
233-
```python
234-
def describe_my_function():
235-
def with_default_arguments():
236-
def with_some_other_arguments():
237-
def it_throws_exception():
238-
def it_handles_exception():
239-
240-
def describe_some_other_function():
241-
def it_returns_true():
242-
def it_returns_false():
243-
```
244-
245-
It has the additional advantage that you can have marks and fixtures that apply
246-
locally to each group of test function.
247-
248-
With pytest, it's possible to organize tests in a similar way with classes.
249-
However, I think classes are awkward. I don't think the convention of using
250-
camel-case names for classes fit very well when testing functions in different
251-
cases. In addition, every test function must take a "self" argument that is
252-
never used.
253-
254-
The pytest-describe plugin allows organizing your tests in the nicer way shown
255-
above using describe-blocks.
256-
257-
## Shared Behaviors
258-
259-
If you've used rspec's shared examples or test class inheritance, then you may
260-
be familiar with the benefit of having the same tests apply to
261-
multiple "subjects" or "suts" (system under test).
262-
263-
```python
264-
from pytest import fixture
265-
from pytest_describe import behaves_like
266-
267-
def a_duck():
268-
def it_quacks(sound):
269-
assert sound == "quack"
270-
271-
@behaves_like(a_duck)
272-
def describe_something_that_quacks():
273-
@fixture
274-
def sound():
275-
return "quack"
276-
277-
# the it_quacks test in this describe will pass
278-
279-
@behaves_like(a_duck)
280-
def describe_something_that_barks():
281-
@fixture
282-
def sound():
283-
return "bark"
284-
285-
# the it_quacks test in this describe will fail (as expected)
286-
```
287-
288-
Fixtures defined in the block that includes the shared behavior take precedence
289-
over fixtures defined in the shared behavior. This rule only applies to
290-
fixtures, not to other functions (nested describe blocks and tests). Instead,
291-
they are all collected as separate tests.
292-
293294
## Accessing describe functions from plugins
294295

295296
Reporting plugins sometimes need to know which describe-blocks enclose a

0 commit comments

Comments
 (0)