diff --git a/tobiko/__init__.py b/tobiko/__init__.py index 15eb24e2a..af985c43f 100644 --- a/tobiko/__init__.py +++ b/tobiko/__init__.py @@ -27,6 +27,8 @@ TobikoException = _exception.TobikoException is_fixture = _fixture.is_fixture get_fixture = _fixture.get_fixture +required_fixture = _fixture.required_fixture +required_setup_fixture = _fixture.required_setup_fixture get_fixture_name = _fixture.get_fixture_name get_fixture_class = _fixture.get_fixture_class get_fixture_dir = _fixture.get_fixture_dir diff --git a/tobiko/common/_fixture.py b/tobiko/common/_fixture.py index 8f5a78c78..9bbac4a5f 100644 --- a/tobiko/common/_fixture.py +++ b/tobiko/common/_fixture.py @@ -118,9 +118,13 @@ def iter_required_fixtures(objects): elif inspect.isclass(obj): members = [obj for _, obj in inspect.getmembers(obj) if (inspect.isfunction(obj) or - inspect.ismethod(obj))] + inspect.ismethod(obj) or + isinstance(obj, RequiredFixtureProperty))] objects.extend(members) + elif isinstance(obj, RequiredFixtureProperty): + objects.append(obj.obj) + def list_required_fixtures(objects): return sorted(set(iter_required_fixtures(objects))) @@ -141,6 +145,14 @@ def init_fixture(obj, name): raise TypeError("Invalid fixture object type: {!r}".format(object)) +def required_fixture(obj): + return RequiredFixtureProperty(obj) + + +def required_setup_fixture(obj): + return RequiredSetupFixtureProperty(obj) + + def get_object_name(obj): if isinstance(obj, six.string_types): return obj @@ -281,3 +293,24 @@ class SharedFixture(fixtures.Fixture): def cleanup_fixture(self): pass + + +class RequiredFixtureProperty(object): + + def __init__(self, obj): + self.obj = obj + + def __get__(self, instance, owner): + if instance is None: + return self + else: + return self.get_fixture() + + def get_fixture(self): + return self.obj + + +class RequiredSetupFixtureProperty(RequiredFixtureProperty): + + def get_fixture(self): + return setup_fixture(self.obj) diff --git a/tobiko/tests/test_fixture.py b/tobiko/tests/test_fixture.py index cd7db61a6..683b8a057 100644 --- a/tobiko/tests/test_fixture.py +++ b/tobiko/tests/test_fixture.py @@ -20,8 +20,27 @@ import tobiko from tobiko.tests import unit +class MyRequiredFixture(tobiko.SharedFixture): + + def __init__(self): + super(MyRequiredFixture, self).__init__() + self.setup_fixture = mock.MagicMock( + specs=tobiko.SharedFixture.setup_fixture) + + +class MyRequiredSetupFixture(tobiko.SharedFixture): + + def __init__(self): + super(MyRequiredSetupFixture, self).__init__() + self.setup_fixture = mock.MagicMock( + specs=tobiko.SharedFixture.setup_fixture) + + class MyFixture(tobiko.SharedFixture): + req_fixture = tobiko.required_fixture(MyRequiredFixture) + req_setup_fixture = tobiko.required_setup_fixture(MyRequiredSetupFixture) + def __init__(self): super(MyFixture, self).__init__() self.setup_fixture = mock.MagicMock( @@ -31,6 +50,9 @@ class MyFixture(tobiko.SharedFixture): MY_FIXTURE_NAME = __name__ + '.' + MyFixture.__name__ +MY_REQUIRED_FIXTURE_NAME = __name__ + '.' + MyRequiredFixture.__name__ +MY_REQUIRED_SETUP_FIXTURE_NAME = ( + __name__ + '.' + MyRequiredSetupFixture.__name__) class FixtureManagerTest(unit.TobikoUnitTest): @@ -106,7 +128,11 @@ class FixtureManagerTest(unit.TobikoUnitTest): def test_list_required_fixtures_from_module(self): result = tobiko.list_required_fixtures([__name__]) - self.assertEqual([MY_FIXTURE_NAME], result) + self.assertEqual( + [MY_FIXTURE_NAME, + MY_REQUIRED_FIXTURE_NAME, + MY_REQUIRED_SETUP_FIXTURE_NAME], + result) def test_list_required_fixtures_from_testcase_type(self): result = tobiko.list_required_fixtures([FixtureManagerTest]) @@ -114,11 +140,19 @@ class FixtureManagerTest(unit.TobikoUnitTest): def test_list_required_fixtures_from_fixture_type(self): result = tobiko.list_required_fixtures([MyFixture]) - self.assertEqual([MY_FIXTURE_NAME], result) + self.assertEqual( + [MY_FIXTURE_NAME, + MY_REQUIRED_FIXTURE_NAME, + MY_REQUIRED_SETUP_FIXTURE_NAME], + result) def test_list_required_fixtures_from_fixture_name(self): result = tobiko.list_required_fixtures([MY_FIXTURE_NAME]) - self.assertEqual([MY_FIXTURE_NAME], result) + self.assertEqual( + [MY_FIXTURE_NAME, + MY_REQUIRED_FIXTURE_NAME, + MY_REQUIRED_SETUP_FIXTURE_NAME], + result) def test_list_required_fixtures_from_method( self, fixture_type=MyFixture): @@ -143,6 +177,10 @@ class SharedFixtureTest(unit.TobikoUnitTest): fixture = MyFixture() fixture.setup_fixture.assert_not_called() fixture.cleanup_fixture.assert_not_called() + self.assertEqual( + MyRequiredFixture, + fixture.req_fixture) + fixture.req_setup_fixture.setup_fixture.assert_called_once() def test_get(self): fixture = MyFixture.get()