Skip to content

Commit 648dead

Browse files
committed
module, tests: set up VCR.py for plugin example tests
* Add new `vcr` kwarg to `module.example` decorator * Considered making this part of `online`, but decided to keep it separate as it would be a pretty big behavior change * Add PyPI requirements for implementing VCR * This involved some trial-and-error, letting Travis flag up incompatibilities on old Python releases I can't install locally * Configure default cassette directory for VCR via new conftest fixture
1 parent 78aeb2f commit 648dead

File tree

4 files changed

+47
-10
lines changed

4 files changed

+47
-10
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ quality:
66
test:
77
coverage run -m py.test -v .
88

9+
test_novcr:
10+
coverage run -m py.test -v . --vcr-record=none
11+
912
coverage_report:
1013
coverage report
1114

@@ -16,7 +19,7 @@ coverages: coverage_report coverage_html
1619

1720
qa: quality test coverages
1821

19-
travis: quality test coverage_report
22+
travis: quality test_novcr coverage_report
2023

2124
clean_docs:
2225
$(MAKE) -C docs clean

conftest.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
import pytest
24

35
# This file lists files which should be ignored by pytest
@@ -24,3 +26,13 @@ def pytest_configure(config):
2426
'markers',
2527
'online: for tests that require online access. '
2628
'Use --offline to skip them.')
29+
30+
31+
@pytest.fixture(scope='module')
32+
def vcr_cassette_dir(request):
33+
# Override VCR.py cassette save location, to keep them out of code folders
34+
parts = request.module.__name__.split('.')
35+
if parts[0] == 'sopel':
36+
# We know it's part of Sopel...
37+
parts = parts[1:]
38+
return os.path.join('test', 'vcr', *parts)

dev-requirements.txt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
pytest<3.3; python_version == '3.3'
2-
pytest>=4.6,<4.7; python_version != '3.3'
31
coveralls
42
flake8<3.6.0; python_version == '3.3'
53
flake8>=3.7.0,<3.8.0; python_version != '3.3'
64
flake8-coding
75
flake8-future-import<0.4.6
6+
pytest<3.3; python_version == '3.3'
7+
pytest>=4.6,<4.7; python_version != '3.3'
8+
pytest-vcr==1.0.2; python_version != '3.3'
9+
pytest-vcr==0.3.0; python_version == '3.3'
10+
PyYAML<5.1; python_version == '3.3'
11+
PyYAML<5.3; python_version == '3.4'
812
setuptools<40.0; python_version == '3.3'
913
sphinx
1014
sphinxcontrib-autoprogram
15+
vcrpy==2.1.1; python_version == '2.7'
16+
vcrpy<1.12.0; python_version == '3.3'
17+
vcrpy<2.1.0; python_version == '3.4'
18+
vcrpy<3.0.0; python_version >= '3.5'

sopel/module.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -736,9 +736,11 @@ class example(object):
736736
:param bool user_help: whether this example should be included in
737737
user-facing help output such as `.help command`
738738
(optional; default ``False``; see below)
739-
:param bool online: if ``True``, |pytest|_ will mark this
740-
example as "online" (optional; default ``False``; see
741-
below)
739+
:param bool online: if ``True``, |pytest|_ will mark this example as
740+
"online" (optional; default ``False``; see below)
741+
:param bool vcr: if ``True``, this example's HTTP requests & responses will
742+
be recorded for later reuse (optional; default ``False``;
743+
see below)
742744
743745
.. |pytest| replace:: ``pytest``
744746
.. _pytest: https://pypi.org/project/pytest/
@@ -766,13 +768,21 @@ class example(object):
766768
can override this choice or include multiple examples by passing
767769
``user_help=True`` to one or more ``example`` decorator(s).
768770
769-
Finally, passing ``online=True`` makes that particular example skippable if
770-
Sopel's test suite is run in offline mode, which is mostly useful to make
771-
life easier for other developers working on Sopel without Internet access.
771+
Passing ``online=True`` makes that particular example skippable if Sopel's
772+
test suite is run in offline mode, which is mostly useful to make life
773+
easier for other developers working on Sopel without Internet access.
774+
775+
Finally, ``vcr=True`` records the example's HTTP requests and responses for
776+
replaying during later test runs. It can be an alternative (or complement)
777+
to ``online``, and is especially useful for testing plugin code that calls
778+
on inconsistent or flaky remote APIs. The recorded "cassettes" of responses
779+
can be committed alongside the code for use by CI services, etc. (See
780+
`VCR.py <https://github.com/kevin1024/vcrpy>`_ & `pytest-vcr
781+
<https://github.com/ktosiek/pytest-vcr>`_)
772782
"""
773783
def __init__(self, msg, result=None, privmsg=False, admin=False,
774784
owner=False, repeat=1, re=False, ignore=None,
775-
user_help=False, online=False):
785+
user_help=False, online=False, vcr=False):
776786
# Wrap result into a list for get_example_test
777787
if isinstance(result, list):
778788
self.result = result
@@ -787,6 +797,7 @@ def __init__(self, msg, result=None, privmsg=False, admin=False,
787797
self.owner = owner
788798
self.repeat = repeat
789799
self.online = online
800+
self.vcr = vcr
790801

791802
if isinstance(ignore, list):
792803
self.ignore = ignore
@@ -820,6 +831,9 @@ def __call__(self, func):
820831
if self.online:
821832
test = pytest.mark.online(test)
822833

834+
if self.vcr:
835+
test = pytest.mark.vcr(test)
836+
823837
sopel.test_tools.insert_into_module(
824838
test, func.__module__, func.__name__, 'test_example'
825839
)

0 commit comments

Comments
 (0)