• Stars
    star
    173
  • Rank 220,124 (Top 5 %)
  • Language
    Python
  • License
    MIT License
  • Created over 2 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

a tool to detect test pollution

build status pre-commit.ci status

detect-test-pollution

a tool to detect test pollution

installation

pip install detect-test-pollution

what is test pollution?

video about test pollution

test pollution is where a test fails due to the side-effects of some other test in the test suite.

it usually appears as a "test flake" something where the test fails mysteriously but passes when run by itself.

a simple example of this is the following python code:

k = 1

def test_k():
    assert k == 1

def test_k2():
    global k

    k = 2
    assert k == 2

now this example is a little bit silly, you probably wouldn't write code this poorly but helps us demonstrate the problem here.

when run normally -- these tests pass:

$ pytest -q t.py
..                                                                       [100%]
2 passed in 0.00s

but, if the tests were run in some other order (due to something like pytest-randomly or pytest-xdist) then the pollution would be apparent:

$ pytest -q t.py::test_k2 t.py::test_k
.F                                                                       [100%]
=================================== FAILURES ===================================
____________________________________ test_k ____________________________________

    def test_k():
>       assert k == 1
E       assert 2 == 1

t.py:4: AssertionError
=========================== short test summary info ============================
FAILED t.py::test_k - assert 2 == 1
1 failed, 1 passed in 0.03s

often this flake happens in a codebase with hundreds or thousands of tests and it's difficult to track down which test is causing the global side-effects.

that's where this tool comes in handy! it helps you find the pair of tests which error when run in order.

usage

video about using detect-test-pollution

once you have identified a failing test, you'll be able to feed it into detect-test-pollution to find the causal test.

the basic mode is to run:

detect-test-pollution \
    --failing-test test.py::test_id_here \
    --tests ./tests

where test.py::test_id_here is the identifier of the failing test and ./tests is the directory where your testsuite lives.

if you've already narrowed down the list of testids further than that, you can specify a --testids-file instead of --tests to speed up discovery:

detect-test-pollution \
    --failing-test test.py::test_id_here \
    --testids-file ./testids

you can usually get a list of testids via pytest --collect-only -q (though you'll need to strip some unrelated lines at the end, such as timing and warning info).

then detect-test-pollution will bisect the list of tests to find the failing one. here's an example bisection from a bug in pytest

$ detect-test-pollution --tests ./testing --failing-test testing/io/test_terminalwriter.py::test_should_do_markup_FORCE_COLOR
discovering all tests...
-> discovered 3140 tests!
ensuring test passes by itself...
-> OK!
ensuring test fails with test group...
-> OK!
running step 1:
- 3139 tests remaining (about 12 steps)
running step 2:
- 1570 tests remaining (about 11 steps)
running step 3:
- 785 tests remaining (about 10 steps)
running step 4:
- 393 tests remaining (about 9 steps)
running step 5:
- 197 tests remaining (about 8 steps)
running step 6:
- 99 tests remaining (about 7 steps)
running step 7:
- 50 tests remaining (about 6 steps)
running step 8:
- 25 tests remaining (about 5 steps)
running step 9:
- 12 tests remaining (about 4 steps)
running step 10:
- 6 tests remaining (about 3 steps)
running step 11:
- 3 tests remaining (about 2 steps)
double checking we found it...
-> the polluting test is: testing/test_terminal.py::TestTerminal::test_report_teststatus_explicit_markup

fuzzing

detect-test-pollution can also be used to "fuzz" out failing tests.

it does this by shuffling the test ids and running the testsuite until it fails.

here's an example execution on a silly testsuite:

$ detect-test-pollution --fuzz --tests t.py
discovering all tests...
-> discovered 1002 tests!
run 1...
-> OK!
run 2...
-> found failing test!
try `detect-test-pollution --failing-test t.py::test_k --tests t.py`!

afterwards you can use the normal mode of detect-test-pollution to find the failing pair.

supported test runners

at the moment only pytest is supported -- though in theory the tool could be adapted to support other python test runners, or even other languages.

More Repositories

1

pyupgrade

A tool (and pre-commit hook) to automatically upgrade syntax for newer versions of the language.
Python
3,498
star
2

reorder-python-imports

Rewrites source to reorder python imports
Python
731
star
3

git-code-debt

A dashboard for monitoring code debt in a git repository.
Python
573
star
4

all-repos

Clone all your repositories and apply sweeping changes.
Python
534
star
5

babi

a text editor
Python
393
star
6

add-trailing-comma

A tool (and pre-commit hook) to automatically add trailing commas to calls and literals.
Python
338
star
7

dead

dead simple python dead code detection
Python
331
star
8

yesqa

Automatically remove unnecessary `# noqa` comments
Python
265
star
9

astpretty

Pretty print the output of python stdlib `ast.parse`.
Python
189
star
10

setup-cfg-fmt

apply a consistent format to `setup.cfg` files
Python
152
star
11

setup-py-upgrade

upgrade a setup.py to declarative metadata
Python
148
star
12

scratch

Haphazard things.
Python
118
star
13

importtime-waterfall

Generate waterfalls from `-Ximporttime` tracing.
Python
108
star
14

setuptools-golang

A setuptools extension for building cpython extensions written in golang.
Python
98
star
15

dockerfile

Parse a dockerfile into a high-level representation using the official go parser
Go
97
star
16

gh-perf-review

hackety tool to view github PRs for a period
Python
81
star
17

re-assert

show where your regex match assertion failed!
Python
81
star
18

covdefaults

A coverage plugin to provide sensible default settings
Python
63
star
19

tokenize-rt

A wrapper around the stdlib `tokenize` which roundtrips.
Python
50
star
20

flake8-typing-imports

flake8 plugin which checks that typing imports are properly guarded
Python
48
star
21

cfgv

Validate configuration and produce human readable error messages
Python
44
star
22

recipes

One day IoT will catch up and then I can use CI
26
star
23

classify-imports

Utilities for refactoring imports in python-like syntax.
Python
23
star
24

nintendo-microcontrollers

control various nintendo consoles with arduino!
Python
22
star
25

awshelp

awshelp forwards arguments to `aws` unless `-h` or `--help` are present
Python
20
star
26

setuptools-golang-examples

Example extensions written for https://github.com/asottile/setuptools-golang
Go
19
star
27

watch-plz

Ensure all of your repositories are watched.
Python
17
star
28

workflows

reusable github workflows / actions
17
star
29

ukkonen

Implementation of bounded Levenshtein distance (Ukkonen)
C++
16
star
30

onigurumacffi

python cffi bindings for the oniguruma regex engine
Python
16
star
31

color-code

Encodes files as color
Python
16
star
32

wat

my brain is full of wat
Python
11
star
33

personal-puppet

serverless puppet to manage my machines
Puppet
11
star
34

shiny-pokemon-scraper

automatically detect tera raid events with guaranteed shiny pokemon
Python
10
star
35

set-delete-branch-on-merge

github does not provide a way to set the `delete_branch_on_merge` as a default
Python
9
star
36

babi-grammars

pip installable package to provide syntax grammars for babi
Python
7
star
37

rubyvenv

Create no-hassle ruby "virtualenvs". No .bashrc, no shims, no cd-magic.
Python
7
star
38

tessdata

pip installable versions of tesseract-ocr data
Python
6
star
39

setuptools-download

setuptools plugin to download external files
Python
6
star
40

pygments-pre-commit

A pygments lexer for pre-commit output.
Python
6
star
41

t

haphazard code snippets
Python
4
star
42

markdown-code-blocks

Generate html from markdown with code-block highlighting
Python
4
star
43

asottile.github.io

Python
4
star
44

hiera-eyaml-sshagent

A hiera-eyaml plugin which uses the ssh agent connected to `SSH_AUTH_SOCK` to encrypt / decrypt values.
Ruby
4
star
45

kensquared

Kotlin
2
star
46

.github

centralized github metadata for asottile
2
star
47

itl

Python
2
star
48

asottile

2
star
49

gnome-terminal-broken

rip
1
star