Skip to content

Instantly share code, notes, and snippets.

@JacobCallahan
Created January 23, 2020 20:50
Show Gist options
  • Save JacobCallahan/d6c816e34663d3affe582c7327f73ded to your computer and use it in GitHub Desktop.
Save JacobCallahan/d6c816e34663d3affe582c7327f73ded to your computer and use it in GitHub Desktop.
Fixture demo
"""Pytest fixtures
Fixtures give you a convenient way to perform setup actions outside of a test.
By limiting or expanding the scope of a fixture, you can cut down on costly setup tasks.
"""
import pytest
import random
import unittest2 # please never
NUM = "0123456789"
ALPHA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def dummy(val):
"""This is the target of our tests (ideally in a separate file)"""
return int(val) * 5
"""pytest searches for these next two named methods in each file.
if present, setup_module will run before tests are ran
teardown_module will run after
you don't need to do anything special to trigger this
"""
def setup_module(module):
print("==================== Setting things up ====================")
def teardown_module(module):
print("==================== Tearing things down ====================")
@pytest.fixture
def good_int():
"""The most basic fixture. This will provide a new value for each test."""
return random.randint(0, 100)
@pytest.fixture
def good_str():
"""By default, a fixture's scope is at the test/function level.
This means that random return values will be different for each test
"""
res = ""
for i in range(5):
res += random.choice(NUM)
return res
@pytest.fixture(scope="module")
def bad_str():
"""To share a common random value (or object), set the scope to module.
Each test in this file, accepting bad_str will then have the same value
"""
res = ""
for i in range(5):
res += random.choice(ALPHA)
return res
@pytest.fixture(scope="session")
def common_int():
"""A scope of session will use the same value for all tests in the same pytest run"""
return random.randint(0, 100)
@pytest.fixture(scope="module")
def important_thing():
"""If things don't go well during a fixture, you can skip any test that expects a value."""
thing = random.choice([True, False])
if not thing:
# I don't want to get a false failure, so skip dependent tests
pytest.skip("Setup failed. Skipping test...")
return thing
@pytest.fixture(scope="class")
def my_cool_thing(request, bad_str):
"""You can even add attributes to a test class (unittest style) using fixtures
note that this fixture also takes in the value of another fixture!
"""
request.cls.my_thing = bad_str
# tests in the class can then reference the value with: self.my_thing
def test_positive_dummy():
"""basic test. uses no fixtures"""
assert dummy(5) == 25
def test_positive_dummy_int(common_int):
"""Experiement with switching common_int to good_int, then check output"""
print(common_int)
result = dummy(common_int)
assert result == common_int * 5
def test_positive_dummy_int2(common_int):
"""Experiement with switching common_int to good_int, then check output"""
print(common_int)
result = dummy(common_int)
assert result == common_int * 5
def test_positive_dummy_str(good_str):
print(good_str)
result = dummy(good_str)
assert isinstance(result, int)
def test_negative_dummy_str(bad_str):
print(bad_str)
try:
result = dummy(good_str)
assert not isinstance(result, int)
except:
assert True
def test_positive_thing(important_thing):
"""This test has a 50% chance of being skipped"""
assert important_thing
# broken, but you can play around with it
@pytest.mark.usefixtures("my_cool_thing")
class UnittestSucks(unittest2.TestCase):
"""Use pytest.mark.usefixtures to accept the previously define class-scoped fixture"""
def __init__(self, *args, **kwargs):
print(args)
print(kwargs)
self.whatever = "sure"
def test_dont_use_unittest(self):
print(self.my_thing)
assert self.my_thing != self.whatever
@JacobCallahan
Copy link
Author

run with pytest -sv fixtures.py for the best experience

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment