diff --git a/ckan/tests/helpers.py b/ckan/tests/helpers.py index 3d316ca46c2..a109d1b9fb3 100644 --- a/ckan/tests/helpers.py +++ b/ckan/tests/helpers.py @@ -15,10 +15,8 @@ and make writing tests so much easier, that it's worth having them despite the potential drawbacks. -Consider using :ref:`fixtures` whenever is possible for setting up initial -state of a test or creating related objects. - -This module is reserved for these very useful functions. +New in CKAN 2.9: Consider using :ref:`fixtures` whenever possible for setting +up the initial state of a test or to create helpers objects like client apps. """ @@ -45,6 +43,22 @@ def reset_db(): """Reset CKAN's database. + Rather than use this function directly, use the ``clean_db`` fixture + either for all tests in a class:: + + @pytest.mark.usefixtures("clean_db") + class TestExample(object): + + def test_example(self): + + or for a single test:: + + class TestExample(object): + + @pytest.mark.usefixtures("clean_db") + def test_example(self): + + If a test class uses the database, then it may call this function in its ``setup()`` method to make sure that it has a clean database to start with (nothing left over from other test classes or from previous test runs). @@ -167,6 +181,15 @@ def post(self, url, *args, **kwargs): def _get_test_app(): """Return a webtest.TestApp for CKAN, with legacy templates disabled. + Don't use this function directly, use the ``app`` fixture:: + + def test_dataset_search(self, app): + + url = h.url_for('dataset.search') + + response = app.get(url) + + For functional tests that need to request CKAN pages or post to the API. Unit tests shouldn't need this. @@ -181,6 +204,20 @@ def _get_test_app(): class FunctionalTestBase(object): """A base class for functional test classes to inherit from. + Deprecated: Use the ``app``, ``clean_db``, ``ckan_config`` and + ``with_plugins`` ref:`fixtures` as needed to create functional test + classes, eg:: + + @pytest.mark.ckan_config('ckan.plugins', 'image_view') + @pytest.mark.usefixtures('with_plugins') + @pytest.mark.usefixtures('clean_db') + class TestDatasetSearch(object): + + def test_dataset_search(self, app): + + url = h.url_for('dataset.search') + response = app.get(url) + Allows configuration changes by overriding _apply_config_changes and resetting the CKAN config after your test class has run. It creates a webtest.TestApp at self.app for your class to use to make HTTP requests diff --git a/ckan/tests/pytest_ckan/fixtures.py b/ckan/tests/pytest_ckan/fixtures.py index 3b98be4c0a3..880bd0b9de3 100644 --- a/ckan/tests/pytest_ckan/fixtures.py +++ b/ckan/tests/pytest_ckan/fixtures.py @@ -37,17 +37,27 @@ @pytest.fixture def ckan_config(request, monkeypatch): - """Configuration object used by application. + """Allows to override the configuration object used by tests - Takes into account config patches introduced by `ckan_config` - mark. For using custom config in the whole test, apply - `ckan_config` mark to it and inject `ckan_config` fixture: + Takes into account config patches introduced by the ``ckan_config`` + mark. + + If you just want to set one or more configuration options for the + scope of a test (or a test class), use the ``ckan_config`` mark:: + + @pytest.mark.ckan_config('ckan.auth.create_unowned_dataset', True) + def test_auth_create_unowned_dataset(): + + # ... + + To use the custom config inside a test, apply the + ``ckan_config`` mark to it and inject the ``ckan_config`` fixture: .. literalinclude:: /../ckan/tests/pytest_ckan/test_fixtures.py :start-after: # START-CONFIG-OVERRIDE :end-before: # END-CONFIG-OVERRIDE - Otherwise, when change only need to be applied locally, use + If the change only needs to be applied locally, use the ``monkeypatch`` fixture .. literalinclude:: /../ckan/tests/test_common.py @@ -65,24 +75,36 @@ def ckan_config(request, monkeypatch): @pytest.fixture def make_app(ckan_config): - """Factory for client app. + """Factory for client app instances. - Prefer using ``app`` instead if you have no need in lazy instantiation. + Unless you need to create app instances lazily for some reason, + use the ``app`` fixture instead. """ return test_helpers._get_test_app @pytest.fixture def app(make_app): - """Instance of client app. + """Returns a client app instance to use in functional tests + + To use it, just add the ``app`` parameter to your test function signature:: + + def test_dataset_search(self, app): + + url = h.url_for('dataset.search') + + response = app.get(url) + + """ return make_app() @pytest.fixture(scope=u"session") def reset_db(): - """Callable for setting DB into initial state. Prefer using - ``clean_db``. + """Callable for resetting the database to the initial state. + + If possible use the ``clean_db`` fixture instead. """ return test_helpers.reset_db @@ -90,31 +112,47 @@ def reset_db(): @pytest.fixture(scope=u"session") def reset_index(): - """Callable for cleaning search index. Prefer using ``clean_index``. + """Callable for cleaning search index. + If possible use the ``clean_index`` fixture instead. """ return search.clear_all @pytest.fixture def clean_db(reset_db): - """Start test with database in initial state. + """Resets the database to the initial state. + + This can be used either for all tests in a class:: + + @pytest.mark.usefixtures("clean_db") + class TestExample(object): + + def test_example(self): + + or for a single test:: + + class TestExample(object): + + @pytest.mark.usefixtures("clean_db") + def test_example(self): + """ reset_db() @pytest.fixture def clean_index(reset_index): - """Start test with empty search index. + """Clear search index before starting the test. """ reset_index() @pytest.fixture def with_plugins(ckan_config): - """Load all plugins specified by ``ckan.plugins`` config option in the - beginning of the test. When test ends (event with fail) unload all - those plugins in reverse order. + """Load all plugins specified by the ``ckan.plugins`` config option + at the beginning of the test. When the test ends (even it fails), it will + unload all the plugins in the reverse order. .. literalinclude:: /../ckan/tests/test_factories.py :start-after: # START-CONFIG-OVERRIDE @@ -125,9 +163,7 @@ def with_plugins(ckan_config): for plugin in plugins: if not ckan.plugins.plugin_loaded(plugin): ckan.plugins.load(plugin) - # ckan.plugins.load_all() yield for plugin in reversed(plugins): if ckan.plugins.plugin_loaded(plugin): ckan.plugins.unload(plugin) - # ckan.plugins.unload_all() diff --git a/ckan/tests/test_coding_standards.py b/ckan/tests/test_coding_standards.py index bcf5347724b..796e135a326 100644 --- a/ckan/tests/test_coding_standards.py +++ b/ckan/tests/test_coding_standards.py @@ -218,7 +218,7 @@ def find_unprefixed_string_literals(filename): for lineno, line in renumerate(lines[:lineno]): try: i = line.rindex(quotes) - if (i > 1) and (line[i - 2:i].lower() == u"ur"): + if (i > 1) and (line[i - 2: i].lower() == u"ur"): col_offset = i - 2 elif (i > 0) and (line[i - 1].lower() in u"rbu"): col_offset = i - 1 @@ -227,7 +227,7 @@ def find_unprefixed_string_literals(filename): break except ValueError: continue - leading = lines[lineno][col_offset - 1:col_offset + 1] + leading = lines[lineno][col_offset - 1: col_offset + 1] if leading[:-1] == u"[": # data['id'] is unambiguous, ignore these continue if leading[-1:] not in u"ub": # Don't allow capital U and B either diff --git a/doc/contributing/testing.rst b/doc/contributing/testing.rst index 3b4b4bdfdc2..c7c4abbfa21 100644 --- a/doc/contributing/testing.rst +++ b/doc/contributing/testing.rst @@ -53,8 +53,8 @@ Fast ``setup_class()`` methods, saved against the ``self`` attribute of test classes, or in test helper modules). - Instead use fixtures that create test objects and return them, and - inject into every method only required fixtures. + Instead use fixtures that create test objects and pass them as parameters, and + inject into every method only the required fixtures. * Where appropriate, use the ``monkeypatch`` `fixture `_ to avoid