Skip to content

Commit

Permalink
Merge pull request #67 from sigmavirus24/test-fixtures
Browse files Browse the repository at this point in the history
Add a pytest fixture for Sessions
  • Loading branch information
sigmavirus24 committed May 29, 2015
2 parents 2a6fdb1 + 852cc36 commit b7bce6f
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 3 deletions.
Empty file added betamax/fixtures/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions betamax/fixtures/pytest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
"""A set of fixtures to integrate Betamax with py.test.
.. autofunction:: betamax_session
"""

from __future__ import absolute_import

import pytest
import requests

from .. import recorder as betamax


@pytest.fixture
def betamax_session(request):
"""Generate a session that has Betamax already installed.
This will create a new :class:`requests.Sesssion` instance that is already
using Betamax with a generated cassette name. The cassette name is
generated by first using the module name from where the test is collected,
then the class name (if it exists), and then the test function name. For
example, if your test is in ``test_stuff.py`` and is the method
``TestStuffClass.test_stuff`` then your cassette name will be
``test_stuff_TestStuffClass_test_stuff``.
:param request:
A request object from pytest giving us context information for the
fixture.
:returns:
An instantiated requests Session wrapped by Betamax.
"""
cassette_name = ''

if request.module is not None:
cassette_name += request.module.__name__ + '.'

if request.cls is not None:
cassette_name += request.cls.__name__ + '.'

cassette_name += request.function.__name__

session = requests.Session()
recorder = betamax.Betamax(session)
recorder.use_cassette(cassette_name)
recorder.start()
request.addfinalizer(recorder.stop)
return session
2 changes: 0 additions & 2 deletions dev-requirements.txt

This file was deleted.

52 changes: 52 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ API
.. autoclass:: betamax.configure.Configuration
:members:

.. automodule:: betamax.fixtures.pytest

Examples
--------

Basic Usage
^^^^^^^^^^^

Let `example.json` be a file in a directory called `cassettes` with the
content:

Expand Down Expand Up @@ -79,6 +83,54 @@ On the other hand, this will raise an exception:
data={"key": "value"})
pytest Integration
^^^^^^^^^^^^^^^^^^

.. versionadded:: 0.5.0

When you install Betamax, it now installs a `pytest`_ fixture by default. To
use it in your tests you need only follow the `instructions`_ on pytest's
documentation. To use the ``betamax_session`` fixture for an entire class of
tests you would do:

.. code-block:: python
# tests/test_http_integration.py
import pytest
@pytest.mark.usefixtures('betamax_session')
class TestMyHttpClient:
def test_get(self, betamax_session):
betamax_session.get('https://httpbin.org/get')
This will generate a cassette name for you, e.g.,
``tests.test_http_integration.TestMyHttpClient.test_get``. After running this
test you would have a cassette file stored in your cassette library directory
named ``tests.test_http_integration.TestMyHttpClient.test_get.json``. To use
this fixture at the module level, you need only do

.. code-block:: python
# tests/test_http_integration.py
import pytest
pytest.mark.usefixtures('betamax_session')
class TestMyHttpClient:
def test_get(self, betamax_session):
betamax_session.get('https://httpbin.org/get')
class TestMyOtherHttpClient:
def test_post(self, betamax_session):
betamax_session.post('https://httpbin.org/post')
.. _pytest: http://pytest.org/latest/
.. _instructions:
http://pytest.org/latest/fixture.html#using-fixtures-from-classes-modules-or-projects


.. _opinions:

Opinions at Work
Expand Down
3 changes: 3 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ def data_for(filename):
package_data={'': ['LICENSE', 'AUTHORS.rst']},
include_package_data=True,
install_requires=requires,
entry_points={
'pytest11': ['pytest-betamax = betamax.fixtures.pytest']
},
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"recorded_with": "betamax/0.4.2", "http_interactions": [{"recorded_at": "2015-05-25T00:46:42", "response": {"body": {"encoding": null, "string": "{\n \"args\": {}, \n \"headers\": {\n \"Accept\": \"*/*\", \n \"Accept-Encoding\": \"gzip, deflate\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\": \"python-requests/2.6.0 CPython/3.4.2 Darwin/14.1.0\"\n }, \n \"origin\": \"72.160.201.47\", \n \"url\": \"https://httpbin.org/get\"\n}\n"}, "status": {"message": "OK", "code": 200}, "url": "https://httpbin.org/get", "headers": {"connection": ["keep-alive"], "content-type": ["application/json"], "content-length": ["266"], "date": ["Mon, 25 May 2015 00:46:42 GMT"], "access-control-allow-origin": ["*"], "access-control-allow-credentials": ["true"], "server": ["nginx"]}}, "request": {"method": "GET", "body": {"encoding": "utf-8", "string": ""}, "uri": "https://httpbin.org/get", "headers": {"Connection": ["keep-alive"], "User-Agent": ["python-requests/2.6.0 CPython/3.4.2 Darwin/14.1.0"], "Accept": ["*/*"], "Accept-Encoding": ["gzip, deflate"]}}}]}
26 changes: 26 additions & 0 deletions tests/integration/test_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import os.path

import pytest


@pytest.mark.usefixtures('betamax_session')
class TestPyTestFixtures:
@pytest.fixture(autouse=True)
def setup(self, request):
"""After test hook to assert everything."""
def finalizer():
test_dir = os.path.abspath('.')
cassette_name = ('tests.integration.test_fixtures.' # Module name
'TestPyTestFixtures.' # Class name
'test_pytest_fixture' # Test function name
'.json')
file_name = os.path.join(test_dir, 'tests', 'cassettes',
cassette_name)
assert os.path.exists(file_name) is True

request.addfinalizer(finalizer)

def test_pytest_fixture(self, betamax_session):
"""Exercise the fixture itself."""
resp = betamax_session.get('https://httpbin.org/get')
assert resp.ok
39 changes: 39 additions & 0 deletions tests/unit/test_fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
try:
import unittest.mock as mock
except ImportError:
import mock

import unittest

import betamax
from betamax.fixtures import pytest as pytest_fixture


class TestPyTestFixture(unittest.TestCase):
def setUp(self):
self.mocked_betamax = mock.MagicMock()
self.patched_betamax = mock.patch.object(
betamax.recorder, 'Betamax', return_value=self.mocked_betamax)
self.patched_betamax.start()

def tearDown(self):
self.patched_betamax.stop()

def test_adds_stop_as_a_finalizer(self):
# Mock a pytest request object
request = mock.MagicMock()
request.cls = request.module = None
request.function.__name__ = 'test'

pytest_fixture.betamax_session(request)
assert request.addfinalizer.called is True
request.addfinalizer.assert_called_once_with(self.mocked_betamax.stop)

def test_auto_starts_the_recorder(self):
# Mock a pytest request object
request = mock.MagicMock()
request.cls = request.module = None
request.function.__name__ = 'test'

pytest_fixture.betamax_session(request)
self.mocked_betamax.start.assert_called_once_with()
16 changes: 15 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ envlist = py26,py27,py32,py33,py34,pypy,{py27,py34}-flake8,docstrings
[testenv]
pip_pre = False
deps =
-rdev-requirements.txt
requests >= 2.0
pytest
pypy: mock
py26: mock
py27: mock
py32: mock
py33: mock
commands = py.test {posargs}

[testenv:py27-flake8]
Expand Down Expand Up @@ -33,6 +39,14 @@ commands =
python setup.py sdist bdist_wheel
twine upload {posargs} dist/*

[testenv:docs]
deps =
sphinx>=1.3.0
pytest
.
commands =
sphinx-build -E -c docs -b html docs/ docs/_build/html

[pytest]
addopts = -q
norecursedirs = *.egg .git .* _*

0 comments on commit b7bce6f

Please sign in to comment.