Create abstract fixture manager

Allow to decople global fixture definition from test
cases.

Fixtures can be defined as a subclass of tobiko.Fixture

  class MyFixture(tobiko.Fixture):
      ...

Tobiko will reference to it as: '<module-name>.MyFixture'
where module-name is the full name of the module where
the class is defined. Fixture name are accessible via
'fixture_name' class attribute.

tobiko.Fixture subclass has to implement bellow methods

  def create_fixture(self):
      # mandatory
      ...

  def delete_fixture(self):
      # optional method
      ...

Test cases to create a fixture should mane one of below
calls:

  fixture = tobiko.create_fixture(<fixture-name>)
  fixture = tobiko.create_fixture(<fixture-class>)

Existing fixtures can be find using one of below calls:

  fixture = tobiko.get_fixture(<fixture-name>)
  fixture = tobiko.get_fixture(<fixture-class>)

Existing fixtures can be deleted using one of below calls:

  tobiko.delete_fixture(<fixture-name>)
  tobiko.delete_fixture(<fixture-class>)

Change-Id: I5c104a732234ab2183fbfb9909cba4a445f59b60
This commit is contained in:
Federico Ressi 2018-12-18 18:02:24 +01:00
parent e790cc131b
commit 487281e7a7
4 changed files with 210 additions and 2 deletions

View File

@ -0,0 +1,22 @@
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
from tobiko.common.managers import fixture as fixture_manager
Fixture = fixture_manager.Fixture
get_fixture = fixture_manager.FIXTURES.get
create_fixture = fixture_manager.FIXTURES.create
delete_fixture = fixture_manager.FIXTURES.delete

View File

@ -0,0 +1,97 @@
# Copyright 2018 Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import abc
import inspect
import six
def get_fixture_name(obj):
if isinstance(obj, six.string_types):
return obj
elif (isinstance(obj, six.class_types) and
issubclass(obj, Fixture)):
return obj.fixture_name
msg = "{!r} is not a string type or a subclass of {!s}".format(
obj, Fixture)
raise TypeError(msg)
class FixtureManager(object):
def __init__(self):
self.fixtures = {}
def set(self, name, cls):
if not issubclass(cls, Fixture):
msg = "{!r} is not a subclass of {!s}".format(cls, Fixture)
raise TypeError(msg)
fixture = cls()
actual_fixture = self.fixtures.setdefault(name, fixture)
if actual_fixture is not fixture:
msg = "Fixture with named {!r} already registered: {!r}".format(
name, actual_fixture)
raise ValueError(msg)
return fixture
def get(self, cls_or_name):
name = get_fixture_name(cls_or_name)
fixture = self.fixtures.get(name)
if fixture is None:
raise ValueError('Invalid fixture name: {!r}'.format(name))
return fixture
def create(self, cls_or_name):
fixture = self.get(cls_or_name)
fixture.create_fixture()
return fixture
def delete(self, cls_or_name):
fixture = self.get(cls_or_name)
fixture.delete_fixture()
return fixture
FIXTURES = FixtureManager()
class FixtureMeta(abc.ABCMeta):
def __new__(cls, name, bases, members):
fixture_class = super(FixtureMeta, cls).__new__(cls, name, bases,
members)
if not inspect.isabstract(fixture_class):
fixture_name = getattr(fixture_class, 'fixture_name', None)
if fixture_name is None:
fixture_class.fixture_name = fixture_name = (
fixture_class.__module__ + '.' +
fixture_class.__name__)
FIXTURES.set(fixture_name, fixture_class)
return fixture_class
@six.add_metaclass(FixtureMeta)
class Fixture(object):
@abc.abstractmethod
def create_fixture(self):
pass
def delete_fixture(self):
pass

View File

@ -0,0 +1,89 @@
# Copyright 2018 Red Hat
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import tobiko
from tobiko.tests import base
class TestFixture(tobiko.Fixture):
def __init__(self):
self.created = False
self.deleted = False
reset = __init__
def create_fixture(self):
self.created = True
def delete_fixture(self):
self.deleted = True
class FixtureTypeTest(base.TobikoTest):
fixture_type = TestFixture
fixture_name = __name__ + '.' + TestFixture.__name__
@classmethod
def setUpClass(cls):
super(FixtureTypeTest, cls).setUpClass()
cls.fixture = tobiko.get_fixture(cls.fixture_name)
def setUp(self):
super(FixtureTypeTest, self).setUp()
self.fixture.reset()
def test_fixture_type(self):
self.assertIsInstance(self.fixture, self.fixture_type)
def test_fixture_name(self):
self.assertEqual(self.fixture_name, self.fixture.fixture_name)
def test_get_fixture_by_name(self):
self._test_get_fixture(self.fixture_name)
def test_get_fixture_by_type(self):
self._test_get_fixture(self.fixture_type)
def _test_get_fixture(self, obj):
fixture = tobiko.get_fixture(obj)
self.assertIs(self.fixture, fixture)
self.assertFalse(fixture.created)
self.assertFalse(fixture.deleted)
def test_create_fixture_by_name(self):
self._test_create_fixture(self.fixture_name)
def test_create_fixture_by_type(self):
self._test_create_fixture(self.fixture_type)
def _test_create_fixture(self, obj):
fixture = tobiko.create_fixture(obj)
self.assertIs(self.fixture, fixture)
self.assertTrue(fixture.created)
self.assertFalse(fixture.deleted)
def test_delete_fixture_by_name(self):
self._test_delete_fixture(self.fixture_name)
def test_delete_fixture_by_type(self):
self._test_delete_fixture(self.fixture_type)
def _test_delete_fixture(self, obj=TestFixture):
fixture = tobiko.delete_fixture(obj)
self.assertIs(self.fixture, fixture)
self.assertFalse(fixture.created)
self.assertTrue(fixture.deleted)

View File

@ -1,5 +1,5 @@
[tox]
envlist = pep8,pylint,py35,py36,py27
envlist = pep8,pylint,py35,py36,py37,py27
minversion = 2.0
@ -24,7 +24,7 @@ commands =
find . -type f -name ".coverage*" -delete
find . -type f -name "*.pyc" -delete
coverage erase
stestr --test-path ./tobiko/tests/cmd run {posargs}
stestr --test-path ./tobiko/tests run --black-regex 'scenario' {posargs}
coverage combine
coverage html -d cover
coverage xml -o cover/coverage.xml