Python pytest workshop part 2
Recap
This is part two of 211209-1354 Python testing basics with poetry and pytest. Fixtures scopes work similarly to the various setup/teardown functions of unittest, can be per module/class/etc.
Failure
Expecting a test to fail
@pytest.mark.xfail(reason="Reason why it's supposed to fail")
def test_...
Expecting a test to raise an exception
For a specific exception, you assert that it raises that exception type and then can do asserts on the exception that is raised.
def test_whatever():
with pytest.raises(Exception) as excinfo:
raise Exception("oh no")
assert str(excinfo.value) == "oh no"
Regex also works (example directly from pytest.raises()
API Reference
>>> with pytest.raises(ValueError, match=r'must be \d+$'):
... raise ValueError("value must be 42")
## Services (skipped, see below)
### Creating fixtures that get used automatically
```python
@pytest.fixture(autouse=True)
def skip_servicetest(request, run_services):
if request....
pytest.skip("skipped because X")
Using the filesystem
pyfakefs
creates a fake filesystem that gets used transparently.
from pyfakefs.fake_filesystem import FakeFilesystem
@pytest.fixture
def common_fs(fs: FakeFilesystem):
fs.create_dir(Path("/tmp/common"))
fs.create_file("/tmp/common")
def test_filesystem_fixture(common_filesystem):
assert os.path.exists("/tmp/common")
assert os.path.exists("/tmp/not_there") == False
General hints
red-green-refactor
A development approach from TDD.
- Red - Write a test, it fails
- Forces us to think about what we want to develop and how do we want to use the interface we’re about to implement.
- Green - Make it pass (as fast as possible)
- If it’s simple, just type it
- If it’s harder, make a note and write the quickest solution that makes the test pass
- Refactor - Spend time to make the implementation correct.
F.I.R.S.T Principles
Tests should be:
- Fast (encourages us to run them frequently, which increases confidence in the code)
- Independent (not influence each other)
- Repeatable (in any environment)
- Self-validating (a failing test should give enough info about what’s wrong1)
- Timely written (just before the production code)2
Arrange-Act-Assert (3A)
3A is a common pattern for structuring tests.
- Arrange -> Create objects / prepare the environment
- Act -> Simulate behaviour
- Assert -> Check the results
In a test this would look like this:
string = "ABc"
result = string.upper()
assert result == "ABC"
Nel mezzo del deserto posso dire tutto quello che voglio.