1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
|
.. doctest-skip-all
Astroquery Testing
==================
Testing in astroquery is a bit more complicated than in other modules since we
depend on remote servers to supply data. In order to keep the tests green and
fast, we use monkeypatching to test most functions on local copies of the data.
In order to set up testing for any given module, you therefore need to have
local copies of the data.
The testing directory structure should look like::
module/tests/__init__.py
module/tests/test_module.py
module/tests/test_module_remote.py
module/tests/setup_package.py
module/tests/data/
module/tests/data/test_data.xml
``test_module.py``
------------------
This file should contain only tests that do not require an internet connection.
It also contains the tricky monkeypatching components. At a minimum, monkeypatching
requires a few methods that are defined locally in the test file for each module.
Monkeypatching
~~~~~~~~~~~~~~
At a minimum, monkeypatching will require these changes:
.. code-block:: python
class MockResponse(object):
def __init__(self, content):
self.content = content
``MockResponse`` is an object intended to have any of the attributes that a
normal `requests.Response` object would have. However, it only needs to
implement the methods that are actually used within the tests.
The tricky bits are in the ``pytest.fixture``.
The first little magical function is the ``patch_x`` function, where ``x`` should
either be ``post`` or ``get``.
.. code-block:: python
@pytest.fixture
def patch_get(request):
try:
mp = request.getfixturevalue("monkeypatch")
except AttributeError: # pytest < 3
mp = request.getfuncargvalue("monkeypatch")
mp.setattr(requests.Session, 'request', get_mockreturn)
return mp
This function, when called, changes the `requests.Session`'s ``request`` method
to call the ``get_mockreturn`` function, defined
below. ``@pytest.fixture`` means that, if any function in this ``test_module.py``
file accepts ``patch_get`` as an argument, ``patch_get`` will be called prior to
running that function.
``get_mockreturn`` is simple but important: this is where you define a function
to return the appropriate data stored in the ``data/`` directory as a readable
object within the ``MockResponse`` class:
.. code-block:: python
def get_mockreturn(url, params=None, timeout=10):
filename = data_path(DATA_FILES['votable'])
content = open(filename, 'r').read()
return MockResponse(content)
``data_path`` is a simple function that looks for the ``data`` directory local to
the ``test_module.py`` file.
.. code-block:: python
def data_path(filename):
data_dir = os.path.join(os.path.dirname(__file__), 'data')
return os.path.join(data_dir, filename)
``test_module_remote.py``
-------------------------
The remote tests are much easier. Just decorate the test class or test
functions with ``astropy.tests.helper.remote_data``.
``setup_package.py``
--------------------
This file only needs the ``get_package_data()`` function, which will tell
``setup.py`` to include the relevant files when installing.
.. code-block:: python
import os
def get_package_data():
paths_test = [os.path.join('data', '*.xml')]
return {'astroquery.module.tests': paths_test}
|