# HG changeset patch # User Denis Laxalde # Date 1452792907 -3600 # Node ID 403a901b6b1e56288bf2ee7ea8d7f2bd7ba2d94c # Parent d7e8912549cd84974b669bd46a91857acb752e58 [devtools] Re-implement generative tests using subtests Generative tests as implemented in logilab.common.testib are not compatible with tests runner other than lgc.pytest and this implementation differs from the standard library, which has support for subtests_ since Python 3.4. Use unittest2 to bridge the gap. Maybe it'd be good to implement this on logilab.common.testlib side at some point. Let's see how this gets received here first. .. _subtests: https://docs.python.org/3/library/unittest.html#subtests diff -r d7e8912549cd -r 403a901b6b1e cubicweb/__pkginfo__.py --- a/cubicweb/__pkginfo__.py Tue Jan 19 10:03:16 2016 +0100 +++ b/cubicweb/__pkginfo__.py Thu Jan 14 18:35:07 2016 +0100 @@ -52,7 +52,8 @@ 'logilab-database': '>= 1.15.0', 'passlib': '', 'pytz': '', - 'Markdown': '' + 'Markdown': '', + 'unittest2': '>= 0.7.0', } __recommends__ = { diff -r d7e8912549cd -r 403a901b6b1e cubicweb/devtools/qunit.py --- a/cubicweb/devtools/qunit.py Tue Jan 19 10:03:16 2016 +0100 +++ b/cubicweb/devtools/qunit.py Thu Jan 14 18:35:07 2016 +0100 @@ -25,7 +25,7 @@ from six.moves.queue import Queue, Empty # imported by default to simplify further import statements -from logilab.common.testlib import unittest_main, with_tempdir, InnerTest, Tags +from logilab.common.testlib import unittest_main, with_tempdir, Tags import webtest.http import cubicweb @@ -109,8 +109,9 @@ depends = args[1] else: depends = () - for js_test in self._test_qunit(test_file, depends): - yield js_test + for name, func, args in self._test_qunit(test_file, depends): + with self.subTest(name=name): + func(*args) @with_tempdir def _test_qunit(self, test_file, depends=(), timeout=10): @@ -127,8 +128,10 @@ browser.start(self.config['base-url'] + "?vid=qunit") test_count = 0 error = False - def raise_exception(cls, *data): - raise cls(*data) + + def runtime_error(*data): + raise RuntimeError(*data) + while not error: try: result, test_name, msg = self.test_queue.get(timeout=timeout) @@ -138,18 +141,16 @@ break test_count += 1 if result: - yield InnerTest(test_name, lambda : 1) + yield test_name, lambda *args: 1, () else: - yield InnerTest(test_name, self.fail, msg) + yield test_name, self.fail, (msg, ) except Empty: error = True msg = '%s inactivity timeout (%is). %i test results received' - yield InnerTest(test_file, raise_exception, RuntimeError, - msg % (test_file, timeout, test_count)) + yield test_file, runtime_error, (msg % (test_file, timeout, test_count), ) browser.stop() if test_count <= 0 and not error: - yield InnerTest(test_name, raise_exception, RuntimeError, - 'No test yielded by qunit for %s' % test_file) + yield test_name, runtime_error, ('No test yielded by qunit for %s' % test_file, ) class QUnitResultController(Controller): diff -r d7e8912549cd -r 403a901b6b1e cubicweb/devtools/repotest.py --- a/cubicweb/devtools/repotest.py Tue Jan 19 10:03:16 2016 +0100 +++ b/cubicweb/devtools/repotest.py Thu Jan 14 18:35:07 2016 +0100 @@ -137,13 +137,14 @@ from rql import RQLHelper +from cubicweb.devtools.testlib import BaseTestCase from cubicweb.devtools.fake import FakeRepo, FakeConfig, FakeSession from cubicweb.server import set_debug, debugged from cubicweb.server.querier import QuerierHelper from cubicweb.server.session import Session from cubicweb.server.sources.rql2sql import SQLGenerator, remove_unused_solutions -class RQLGeneratorTC(TestCase): +class RQLGeneratorTC(BaseTestCase): schema = backend = None # set this in concrete class @classmethod diff -r d7e8912549cd -r 403a901b6b1e cubicweb/devtools/test/unittest_qunit.py --- a/cubicweb/devtools/test/unittest_qunit.py Tue Jan 19 10:03:16 2016 +0100 +++ b/cubicweb/devtools/test/unittest_qunit.py Thu Jan 14 18:35:07 2016 +0100 @@ -17,9 +17,9 @@ js_tests = list(self._test_qunit(js('test_simple_failure.js'))) self.assertEqual(len(js_tests), 3) test_1, test_2, test_3 = js_tests - self.assertRaises(self.failureException, test_1[0], *test_1[1:]) - self.assertRaises(self.failureException, test_2[0], *test_2[1:]) - test_3[0](*test_3[1:]) + self.assertRaises(self.failureException, test_1[1], *test_1[2:]) + self.assertRaises(self.failureException, test_2[1], *test_2[2:]) + test_3[1](*test_3[2:]) if __name__ == '__main__': diff -r d7e8912549cd -r 403a901b6b1e cubicweb/devtools/testlib.py --- a/cubicweb/devtools/testlib.py Tue Jan 19 10:03:16 2016 +0100 +++ b/cubicweb/devtools/testlib.py Thu Jan 14 18:35:07 2016 +0100 @@ -31,7 +31,7 @@ import yams.schema -from logilab.common.testlib import TestCase, InnerTest, Tags +from logilab.common.testlib import TestCase, Tags from logilab.common.pytest import nocoverage from logilab.common.debugger import Debugger from logilab.common.umessage import message_from_string @@ -51,6 +51,16 @@ from cubicweb.devtools import fake, htmlparser, DEFAULT_EMPTY_DB_ID +if sys.version_info[:2] < (3, 4): + import unittest2 + if not hasattr(unittest2.TestCase, 'subTest'): + raise ImportError('no subTest support in available unittest2') + class BaseTestCase(unittest2.TestCase, TestCase): + """Mix of logilab.common.testlib.TestCase and unittest2.TestCase""" +else: + BaseTestCase = TestCase + + # low-level utilities ########################################################## class CubicWebDebugger(Debugger): @@ -253,7 +263,7 @@ # base class for cubicweb tests requiring a full cw environments ############### -class CubicWebTC(TestCase): +class CubicWebTC(BaseTestCase): """abstract class for test using an apptest environment attributes: @@ -1238,18 +1248,19 @@ propdefs[k]['default'] = True for view in self.list_views_for(rset): backup_rset = rset.copy(rset.rows, rset.description) - yield InnerTest(self._testname(rset, view.__regid__, 'view'), - self.view, view.__regid__, rset, - rset.req.reset_headers(), 'main-template') + with self.subTest(name=self._testname(rset, view.__regid__, 'view')): + self.view(view.__regid__, rset, + rset.req.reset_headers(), 'main-template') # We have to do this because some views modify the # resultset's syntax tree rset = backup_rset for action in self.list_actions_for(rset): - yield InnerTest(self._testname(rset, action.__regid__, 'action'), - self._test_action, action) + with self.subTest(name=self._testname(rset, action.__regid__, 'action')): + self._test_action(action) for box in self.list_boxes_for(rset): w = [].append - yield InnerTest(self._testname(rset, box.__regid__, 'box'), box.render, w) + with self.subTest(self._testname(rset, box.__regid__, 'box')): + box.render(w) @staticmethod def _testname(rset, objid, objtype): @@ -1277,19 +1288,18 @@ def test_one_each_config(self): self.auto_populate(1) for rset in self.iter_automatic_rsets(limit=1): - for testargs in self._test_everything_for(rset): - yield testargs + self._test_everything_for(rset) def test_ten_each_config(self): self.auto_populate(10) for rset in self.iter_automatic_rsets(limit=10): - for testargs in self._test_everything_for(rset): - yield testargs + self._test_everything_for(rset) def test_startup_views(self): for vid in self.list_startup_views(): with self.admin_access.web_request() as req: - yield self.view, vid, None, req + with self.subTest(vid=vid): + self.view(vid, None, req) # registry instrumentization ################################################### diff -r d7e8912549cd -r 403a901b6b1e debian/control --- a/debian/control Tue Jan 19 10:03:16 2016 +0100 +++ b/debian/control Thu Jan 14 18:35:07 2016 +0100 @@ -11,7 +11,7 @@ python-six (>= 1.4.0), python-sphinx, python-logilab-common, - python-unittest2 | python (>= 2.7), + python-unittest2 (>= 0.7.0) | python (>= 3.4), python-logilab-mtconverter, python-markdown, python-tz,