Skip to content

Commit 82d2685

Browse files
Make compatible with Sentry SDK 3.0.0 (#39)
This PR: - made pytest-sentry compatible with Sentry Python SDK 3.0.0 - split up the code into modules - updated the README to have a Quickstart section. NOTE: When this PR is released, pytest-sentry is not compatible to SDK 2.x anymore! --------- Co-authored-by: Neel Shah <[email protected]>
1 parent 07ccd88 commit 82d2685

18 files changed

+594
-488
lines changed

README.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# pytest-sentry
2+
3+
[![PyPI](https://img.shields.io/pypi/v/pytest-sentry)](https://pypi.org/project/pytest-sentry/)
4+
[![License](https://img.shields.io/pypi/l/pytest-sentry)](https://pypi.org/project/pytest-sentry/)
5+
6+
`pytest-sentry` is a [pytest](https://pytest.org>) plugin that uses [Sentry](https://sentry.io/) to store and aggregate information about your testruns.
7+
8+
> [!IMPORTANT]
9+
> **This is not an official Sentry product.**
10+
11+
![Screenshot of tracing data of a pytest test suite](assets/pytest-sentry-screenshot.png)
12+
13+
This is what a test run will look like in Sentry.
14+
15+
## Quickstart
16+
### Prerequisites
17+
18+
* You are using [pytest](https://pytest.org) to run your tests.
19+
* You are using [pytest-rerunfailures](https://github.com/pytest-dev/pytest-rerunfailures) to rerun flaky tests.
20+
21+
### Configuration
22+
23+
You can configure `pytest-sentry` with environment variables:
24+
25+
* `PYTEST_SENTRY_DSN`: The Sentry DSN to send the data to.
26+
27+
* `PYTEST_SENTRY_ALWAYS_REPORT`: If not set, only flaky tests are reported as errors. If set to `1` all test failures are reported. If set to `0` no test failures are reported at all.
28+
29+
* `PYTEST_SENTRY_TRACES_SAMPLE_RATE`: The sample rate for tracing data. See https://docs.sentry.io/platforms/python/configuration/options/#traces_sample_rate
30+
31+
* `PYTEST_SENTRY_PROFILES_SAMPLE_RATE`: The sample rate for profiling data.
32+
33+
* `PYTEST_SENTRY_DEBUG`: Set to `1` to display Sentry debug output. See https://docs.sentry.io/platforms/python/configuration/options/#debug
34+
35+
### Running
36+
37+
If you have `pytest-rerunfailures` plugin enabled you set the environment variables and run `pytest` as usual:
38+
```bash
39+
export PYTEST_SENTRY_DSN="https://[email protected]/xxx" # your DSN
40+
export PYTEST_SENTRY_TRACES_SAMPLE_RATE=1
41+
export PYTEST_SENTRY_PROFILES_SAMPLE_RATE=1
42+
export SENTRY_ENVIRONMENT="test-suite"
43+
44+
pytest --reruns=5
45+
```
46+
47+
Now all flaky tests will report to the configured DSN in Sentry.io including trace information and profiles of your tests and test fixtures in an Sentry environment calld `test-suite`.
48+
49+
# Tracking flaky tests as errors
50+
51+
Let's say you have a testsuite with some flaky tests that randomly break your
52+
CI build due to network issues, race conditions or other stuff that you don't
53+
want to fix immediately. The known workaround is to retry those tests
54+
automatically, for example using [pytest-rerunfailures](https://github.com/pytest-dev/pytest-rerunfailures).
55+
56+
One concern against plugins like this is that they just hide the bugs in your
57+
testsuite or even other code. After all your CI build is green and your code
58+
probably works most of the time.
59+
60+
`pytest-sentry` tries to make that choice a bit easier by tracking flaky test
61+
failures in a place separate from your build status. Sentry is already a
62+
good choice for keeping tabs on all kinds of errors, important or not, in
63+
production, so let's try to use it in testsuites too.
64+
65+
The prerequisite is that you already make use of `pytest` and
66+
`pytest-rerunfailures` in CI. Now install `pytest-sentry` and set the
67+
`PYTEST_SENTRY_DSN` environment variable to the DSN of a new Sentry project.
68+
69+
Now every test failure that is "fixed" by retrying the test is reported to
70+
Sentry, but still does not break CI. Tests that consistently fail will not be
71+
reported.
72+
73+
# Tracking the performance of your testsuite
74+
75+
By default `pytest-sentry` will send [Performance](https://sentry.io/for/performance/) data to Sentry:
76+
77+
* Fixture setup is reported as "transaction" to Sentry, such that you can
78+
answer questions like "what is my slowest test fixture" and "what is my most
79+
used test fixture".
80+
81+
* Calls to the test function itself are reported as separate transaction such
82+
that you can find large, slow tests as well.
83+
84+
* Fixture setup related to a particular test item will be in the same trace,
85+
i.e. will have same trace ID. There is no common parent transaction though.
86+
It is purposefully dropped to spare quota as it does not contain interesting
87+
information::
88+
89+
pytest.runtest.protocol [one time, not sent]
90+
pytest.fixture.setup [multiple times, sent]
91+
pytest.runtest.call [one time, sent]
92+
93+
The trace is per-test-item. For correlating transactions across an entire
94+
test run, use the automatically attached CI tags or attach some tag on your
95+
own.
96+
97+
To measure performance data, install `pytest-sentry` and set
98+
`PYTEST_SENTRY_DSN`, like with errors. By default, the extension will send all
99+
performance data to Sentry. If you want to limit the amount of data sent, you
100+
can set the `PYTEST_SENTRY_TRACES_SAMPLE_RATE` environment variable to a float
101+
between `0` and `1`. This will cause only a random sample of transactions to
102+
be sent to Sentry.
103+
104+
Transactions can have noticeable runtime overhead over just reporting errors.
105+
To disable, use a marker::
106+
107+
import pytest
108+
import pytest_sentry
109+
110+
pytestmarker = pytest.mark.sentry_client({"traces_sample_rate": 0.0})
111+
112+
# Advanced Options
113+
114+
`pytest-sentry` supports marking your tests to use a different DSN, client or
115+
scope per-test. You can use this to provide custom options to the `Client`
116+
object from the [Sentry SDK for Python](https://github.com/getsentry/sentry-python):
117+
118+
```python
119+
import random
120+
import pytest
121+
122+
from sentry_sdk import Scope
123+
from pytest_sentry import Client
124+
125+
@pytest.mark.sentry_client(None)
126+
def test_no_sentry():
127+
# Even though flaky, this test never gets reported to sentry
128+
assert random.random() > 0.5
129+
130+
@pytest.mark.sentry_client("MY NEW DSN")
131+
def test_custom_dsn():
132+
# Use a different DSN to report errors for this one
133+
assert random.random() > 0.5
134+
135+
# Other invocations:
136+
137+
@pytest.mark.sentry_client(Client("CUSTOM DSN"))
138+
@pytest.mark.sentry_client(lambda: Client("CUSTOM DSN"))
139+
@pytest.mark.sentry_client(Scope(Client("CUSTOM DSN")))
140+
@pytest.mark.sentry_client({"dsn": ..., "debug": True})
141+
```
142+
143+
The `Client` class exposed by `pytest-sentry` only has different default
144+
integrations. It disables some of the error-capturing integrations to avoid
145+
sending random expected errors into your project.
146+
147+
# Accessing the used Sentry client
148+
149+
You will notice that the global functions such as
150+
`sentry_sdk.capture_message` will not actually send events into the same DSN
151+
you configured this plugin with. That's because `pytest-sentry` goes to
152+
extreme lenghts to keep its own SDK setup separate from the SDK setup of the
153+
tested code.
154+
155+
`pytest-sentry` exposes the `sentry_test_scope` fixture whose return value is
156+
the `Scope` being used to send events to Sentry. Use `with use_scope(entry_test_scope):`
157+
to temporarily switch context. You can use this to set custom tags like so::
158+
159+
```python
160+
def test_foo(sentry_test_scope):
161+
with use_scope(sentry_test_scope):
162+
sentry_sdk.set_tag("pull_request", os.environ['EXAMPLE_CI_PULL_REQUEST'])
163+
```
164+
165+
Why all the hassle with the context manager? Just imagine if your tested
166+
application would start to log some (expected) errors on its own. You would
167+
immediately exceed your quota!
168+
169+
# Always reporting test failures
170+
171+
You can always report all test failures to Sentry by setting the environment
172+
variable `PYTEST_SENTRY_ALWAYS_REPORT=1`.
173+
174+
This can be enabled for builds on the `main` or release branch, to catch
175+
certain kinds of tests that are flaky across builds, but consistently fail or
176+
pass within one testrun.
177+
178+
# License
179+
180+
Licensed under 2-clause BSD, see [LICENSE](LICENSE).

README.rst

Lines changed: 0 additions & 154 deletions
This file was deleted.

assets/pytest-sentry-screenshot.png

336 KB
Loading

0 commit comments

Comments
 (0)