-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #72 from sigmavirus24/unittest-integration
Unittest Integration
- Loading branch information
Showing
8 changed files
with
300 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
"""Minimal :class:`unittest.TestCase` subclass adding Betamax integration. | ||
.. autoclass:: betamax.fixtures.unittest.BetamaxTestCase | ||
:members: | ||
When using Betamax with unittest, you can use the traditional style of Betamax | ||
covered in the documentation thoroughly, or you can use your fixture methods, | ||
:meth:`unittest.TestCase.setUp` and :meth:`unittest.TestCase.tearDown` to wrap | ||
entire tests in Betamax. | ||
Here's how you might use it: | ||
.. code-block:: python | ||
from betamax.fixtures import unittest | ||
from myapi import SessionManager | ||
class TestMyApi(unittest.BetamaxTestCase): | ||
def setUp(self): | ||
# Call BetamaxTestCase's setUp first to get a session | ||
super(TestMyApi, self).setUp() | ||
self.manager = SessionManager(self.session) | ||
def test_all_users(self): | ||
\"\"\"Retrieve all users from the API.\"\"\" | ||
for user in self.manager: | ||
# Make assertions or something | ||
Alternatively, if you are subclassing a :class:`requests.Session` to provide | ||
extra functionality, you can do something like this: | ||
.. code-block:: python | ||
from betamax.fixtures import unittest | ||
from myapi import Session, SessionManager | ||
class TestMyApi(unittest.BetamaxTestCase): | ||
SESSION_CLASS = Session | ||
# See above ... | ||
""" | ||
# NOTE(sigmavirus24): absolute_import is required to make import unittest work | ||
from __future__ import absolute_import | ||
|
||
import unittest | ||
|
||
import requests | ||
|
||
from .. import recorder | ||
|
||
|
||
__all__ = ('BetamaxTestCase',) | ||
|
||
|
||
class BetamaxTestCase(unittest.TestCase): | ||
|
||
"""Betamax integration for unittest. | ||
.. versionadded:: 0.5.0 | ||
""" | ||
|
||
#: Class that is a subclass of :class:`requests.Session` | ||
SESSION_CLASS = requests.Session | ||
|
||
def generate_cassette_name(self): | ||
"""Generates a cassette name for the current test. | ||
The default format is "%(classname)s.%(testMethodName)s" | ||
To change the default cassette format, override this method in a | ||
subclass. | ||
:returns: Cassette name for the current test. | ||
:rtype: str | ||
""" | ||
cls = getattr(self, '__class__') | ||
test = self._testMethodName | ||
return '{0}.{1}'.format(cls.__name__, test) | ||
|
||
def setUp(self): | ||
"""Betamax-ified setUp fixture. | ||
This will call the superclass' setUp method *first* and then it will | ||
create a new :class:`requests.Session` and wrap that in a Betamax | ||
object to record it. At the end of ``setUp``, it will start recording. | ||
""" | ||
# Bail out early if the SESSION_CLASS isn't a subclass of | ||
# requests.Session | ||
self.assertTrue(issubclass(self.SESSION_CLASS, requests.Session)) | ||
# Make sure if the user is multiply inheriting that all setUps are | ||
# called. (If that confuses you, see: https://youtu.be/EiOglTERPEo) | ||
super(BetamaxTestCase, self).setUp() | ||
|
||
cassette_name = self.generate_cassette_name() | ||
|
||
self.session = self.SESSION_CLASS() | ||
self.recorder = recorder.Betamax(session=self.session) | ||
self.recorder.use_cassette(cassette_name) | ||
self.recorder.start() | ||
|
||
def tearDown(self): | ||
"""Betamax-ified tearDown fixture. | ||
This will call the superclass' tearDown method *first* and then it | ||
will stop recording interactions. | ||
""" | ||
super(BetamaxTestCase, self).tearDown() | ||
self.recorder.stop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
Integrating Betamax with Test Frameworks | ||
======================================== | ||
|
||
It's nice to have a way to integrate libraries you use for testing into your | ||
testing frameworks. Having considered this, the authors of and contributors to | ||
Betamax have included integrations in the package. Betamax comes with | ||
integrations for py.test and unittest. (If you need an integration for another | ||
framework, please suggest it and send a patch!) | ||
|
||
PyTest Integration | ||
------------------ | ||
|
||
.. versionadded:: 0.5.0 | ||
|
||
When you install Betamax, it now installs a `py.test`_ 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') | ||
Unittest Integration | ||
-------------------- | ||
|
||
.. versionadded:: 0.5.0 | ||
|
||
When writing tests with unittest, a common pattern is to either import | ||
:class:`unittest.TestCase` or subclass that and use that subclass in your | ||
tests. When integrating Betamax with your unittest testsuite, you should do | ||
the following: | ||
|
||
.. code-block:: python | ||
from betamax.fixtures import unittest | ||
class IntegrationTestCase(unitest.BetamaxTestCase): | ||
# Add your the rest of the helper methods you want for your | ||
# integration tests | ||
class SpecificTestCase(IntegrationTestCase): | ||
def test_something(self): | ||
# Test something | ||
The unittest integration provides the following attributes on the test case | ||
instance: | ||
|
||
- ``session`` the instance of ``BetamaxTestCase.SESSION_CLASS`` created for | ||
that test. | ||
|
||
- ``recorder`` the instance of :class:`betamax.Betamax` created. | ||
|
||
The integration also generates a cassette name from the test case class name | ||
and test method. So the cassette generated for the above example would be | ||
named ``SpecificTestCase.test_something``. To override that behaviour, you | ||
need to override the | ||
:meth:`~betamax.fixtures.BetamaxTestCase.generate_cassette_name` method in | ||
your subclass. | ||
|
||
If you are subclassing :class:`requests.Session` in your application, then it | ||
follows that you will want to use that in your tests. To facilitate this, you | ||
can set the ``SESSION_CLASS`` attribute. To give a fuller example, let's say | ||
you're changing the default cassette name and you're providing your own | ||
session class, your code might look like: | ||
|
||
.. code-block:: python | ||
from betamax.fixtures import unittest | ||
from myapi import session | ||
class IntegrationTestCase(unitest.BetamaxTestCase): | ||
# Add your the rest of the helper methods you want for your | ||
# integration tests | ||
SESSION_CLASS = session.MyApiSession | ||
def generate_cassette_name(self): | ||
classname = self.__class__.__name__ | ||
method = self._testMethodName | ||
return 'integration_{0}_{1}'.format(classname, method) | ||
.. _py.test: http://pytest.org/latest/ | ||
.. _instructions: | ||
http://pytest.org/latest/fixture.html#using-fixtures-from-classes-modules-or-projects |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.