diff --git a/doc/test-framework.rst b/doc/test-framework.rst index f53d15ae0da..17a7b480640 100644 --- a/doc/test-framework.rst +++ b/doc/test-framework.rst @@ -104,3 +104,14 @@ TestCase subclasses .. automodule:: openerp.tests.common :members: + +.. note:: + + The `setUp` and `tearDown` methods are not part of the tests. Uncaught + exceptions in those methods are errors, not test failures. In particular, + a failing `setUp` will not be followed by a `tearDown` causing any + allocated resource in the `setUp` to not be released by the `tearDown`. + + In the :py:class:`openerp.tests.common.TransactionCase` and + :py:class:`openerp.tests.common.SingleTransactionCase`, this means the + test suite can hang because of unclosed cursors. diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index d06e1030d6f..aa39b777c0f 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -9,7 +9,7 @@ See the :ref:`test-framework` section in the :ref:`features` list. """ from . import test_expression, test_html_sanitize, test_ir_sequence, test_orm,\ - test_per_class_teardown, \ + test_basecase, \ test_view_validation, test_uninstall, test_misc, test_db_cursor fast_suite = [ @@ -21,7 +21,7 @@ checks = [ test_html_sanitize, test_db_cursor, test_orm, - test_per_class_teardown, + test_basecase, test_view_validation, test_misc, ] diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 26ad1e5b5c2..3cc8b126c02 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- """ -The module :mod:`openerp.tests.common` provides a few helper and classes to write +The module :mod:`openerp.tests.common` provides a few helpers and classes to write tests. """ -import os import threading import time import unittest2 @@ -44,10 +43,11 @@ def stop_openerp(): """ openerp.service.stop_services() - class BaseCase(unittest2.TestCase): """ Subclass of TestCase for common OpenERP-specific code. + + This class is abstract and expects self.cr and self.uid to be initialized by subclasses. """ @classmethod @@ -58,6 +58,29 @@ class BaseCase(unittest2.TestCase): def registry(self, model): return openerp.modules.registry.RegistryManager.get(DB)[model] + @classmethod + def ref(self, xid): + """ Returns database ID corresponding to a given identifier. + + :param xid: fully-qualified record identifier, in the form ``module.identifier`` + :raise: ValueError if not found + """ + assert "." in xid, "this method requires a fully qualified parameter, in the following form: 'module.identifier'" + module, xid = xid.split('.') + _, id = self.registry('ir.model.data').get_object_reference(self.cr, self.uid, module, xid) + return id + + @classmethod + def browse_ref(self, xid): + """ Returns a browsable record for the given identifier. + + :param xid: fully-qualified record identifier, in the form ``module.identifier`` + :raise: ValueError if not found + """ + assert "." in xid, "this method requires a fully qualified parameter, in the following form: 'module.identifier'" + module, xid = xid.split('.') + return self.registry('ir.model.data').get_object(self.cr, self.uid, module, xid) + class TransactionCase(BaseCase): """ diff --git a/openerp/tests/test_per_class_teardown.py b/openerp/tests/test_basecase.py similarity index 60% rename from openerp/tests/test_per_class_teardown.py rename to openerp/tests/test_basecase.py index a1890095c09..55125b6d7c2 100644 --- a/openerp/tests/test_per_class_teardown.py +++ b/openerp/tests/test_basecase.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- import unittest2 -import openerp import common -class test_per_class_teardown(common.SingleTransactionCase): +class test_single_transaction_case(common.SingleTransactionCase): """ Check the whole-class transaction behavior of SingleTransactionCase. """ @@ -22,7 +21,30 @@ class test_per_class_teardown(common.SingleTransactionCase): ids = self.registry('res.partner').search(cr, uid, [('name', '=', 'test_per_class_teardown_partner')]) self.assertEqual(1, len(ids), "Test partner not found.") -class test_per_method_teardown(common.TransactionCase): + def test_20a(self): + """ Create a partner with a XML ID """ + cr, uid = self.cr, self.uid + res_partner = self.registry('res.partner') + ir_model_data = self.registry('ir.model.data') + pid, _ = res_partner.name_create(cr, uid, 'Mr Blue') + ir_model_data.create(cr, uid, {'name': 'test_partner_blue', + 'module': 'base', + 'model': 'res.partner', + 'res_id': pid}) + def test_20b(self): + """ Resolve xml id with ref() and browse_ref() """ + cr, uid = self.cr, self.uid + res_partner = self.registry('res.partner') + xid = 'base.test_partner_blue' + p_ref = self.ref(xid) + self.assertTrue(p_ref, "ref() should resolve xid to database ID") + partner = res_partner.browse(cr, uid, p_ref) + p_browse_ref = self.browse_ref(xid) + self.assertEqual(partner, p_browse_ref, "browse_ref() should resolve xid to browse records") + + + +class test_transaction_case(common.TransactionCase): """ Check the per-method transaction behavior of TransactionCase. """ diff --git a/openerp/tools/yaml_import.py b/openerp/tools/yaml_import.py index 5defce5b655..ca7ab92a225 100644 --- a/openerp/tools/yaml_import.py +++ b/openerp/tools/yaml_import.py @@ -381,7 +381,11 @@ class YamlInterpreter(object): return False return val - view = view_info and etree.fromstring(view_info['arch'].encode('utf-8')) or False + if view_info: + arch = etree.fromstring(view_info['arch'].encode('utf-8')) + view = arch if len(arch) else False + else: + view = False fields = fields or {} if view is not False: fg = view_info['fields']