Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Commit

Permalink
Fixture Refactoring
Browse files Browse the repository at this point in the history
Modify the functional decorator to be a fixture instead because it appears there is a race condition with the `patch` decorator when handled that way.
  • Loading branch information
sernst committed May 29, 2018
1 parent cd3daff commit 442054a
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 41 deletions.
30 changes: 10 additions & 20 deletions cauldron/steptest/functional.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import inspect
import os
import sys
import tempfile
Expand All @@ -12,30 +11,23 @@


class CauldronTest:
"""A Decorator class for use with the Pytest testing framework."""
"""
A Dependency injection class for use with the Pytest or similar testing
framework.
"""

def __init__(self, *args, **kwargs):
def __init__(self, project_path: str, *args, **kwargs):
"""
Initializes the decorator with default values that will be populated
during the lifecycle of the decorator and test.
"""
self.project_path = os.path.realpath(project_path)
self._call_args = args
self._call_kwargs = kwargs
self._test_function = None
self.results_directory = None
self.temp_directories = dict()

def __call__(self, test_function):
"""
Executed during decoration, this function wraps the supplied test
function and returns a wrapped function that should be called to
executed the step test.
"""
self._test_function = test_function

def cauldron_test_wrapper(*args, **kwargs):
return self.run_test(*args, **kwargs)

project_path = self.make_project_path('cauldron.json')
self._library_paths = support.get_library_paths(project_path)
sys.path.extend(self._library_paths)
Expand All @@ -45,10 +37,7 @@ def cauldron_test_wrapper(*args, **kwargs):
# patching isn't reverted.
runner.reload_libraries(self._library_paths)

cauldron_test_wrapper.__name__ = test_function.__name__
return cauldron_test_wrapper

def setup(self):
def setup(self) -> 'CauldronTest':
"""
Handles initializing the environment and opening the project for
testing.
Expand All @@ -62,6 +51,8 @@ def setup(self):
self.temp_directories = dict()
self.open_project()

return self

def make_project_path(self, *args) -> str:
"""
Returns an absolute path to the specified location within the Cauldron
Expand All @@ -74,8 +65,7 @@ def make_project_path(self, *args) -> str:
components are specified, the location returned will be the
project directory itself.
"""
filename = inspect.getfile(self._test_function)
project_directory = support.find_project_directory(filename)
project_directory = support.find_project_directory(self.project_path)
return os.path.join(project_directory, *args)

def open_project(self) -> 'exposed.ExposedProject':
Expand Down
36 changes: 15 additions & 21 deletions cauldron/test/steptesting/test_functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@
from cauldron.steptest import CauldronTest


@CauldronTest()
@pytest.fixture(name='tester')
def tester_fixture() -> CauldronTest:
"""Create the Cauldron project test environment"""
tester = CauldronTest(project_path=os.path.dirname(__file__))
tester.setup()
yield tester
tester.tear_down()


def test_first_step(tester: CauldronTest):
"""Should not be any null/NaN values in df"""
assert cd.shared.fetch('df') is None
Expand All @@ -21,7 +29,6 @@ def test_first_step(tester: CauldronTest):
assert error_echo == ''


@CauldronTest()
def test_second_step(tester: CauldronTest):
"""
Should fail without exception because of an exception raised in the
Expand All @@ -34,7 +41,6 @@ def test_second_step(tester: CauldronTest):
assert 0 < len(error_echo)


@CauldronTest()
def test_second_step_strict(tester: CauldronTest):
"""
Should fail because of an exception raised in the source when strict
Expand All @@ -45,10 +51,9 @@ def test_second_step_strict(tester: CauldronTest):


@patch('_testlib.patching_test')
@CauldronTest()
def test_second_step_with_patching(
tester: CauldronTest,
patching_test: MagicMock
patching_test: MagicMock,
tester: CauldronTest
):
"""Should override the return value with the patch"""
patching_test.return_value = 12
Expand All @@ -58,15 +63,13 @@ def test_second_step_with_patching(
assert 12 == cd.shared.result


@CauldronTest()
def test_second_step_without_patching(tester: CauldronTest):
"""Should succeed running the step without patching"""
cd.shared.value = 42
tester.run_step('S03-lib-patching.py')
assert 42 == cd.shared.result


@CauldronTest()
def test_to_strings(tester: CauldronTest):
"""Should convert list of integers to a list of strings"""
before = [1, 2, 3]
Expand All @@ -76,7 +79,6 @@ def test_to_strings(tester: CauldronTest):
assert ['1', '2', '3'] == after


@CauldronTest()
def test_modes(tester: CauldronTest):
"""Should be testing and not interactive or single run"""
step = tester.run_step('S01-first.py')
Expand All @@ -86,34 +88,30 @@ def test_modes(tester: CauldronTest):
assert not step.local.is_single_run


@CauldronTest()
def test_find_in_current_path(tester: CauldronTest):
def test_find_in_current_path():
"""Should find a project in this file's directory"""
directory = os.path.dirname(os.path.realpath(__file__))
result = steptest.find_project_directory(directory)
assert directory == result


@CauldronTest()
def test_find_in_parent_path(tester: CauldronTest):
def test_find_in_parent_path():
"""Should find a project in the parent directory"""
directory = os.path.dirname(os.path.realpath(__file__))
subdirectory = os.path.join(directory, 'fake')
result = steptest.find_project_directory(subdirectory)
assert directory == result


@CauldronTest()
def test_find_in_grandparent_path(tester: CauldronTest):
def test_find_in_grandparent_path():
"""Should find a project in the grandparent directory"""
directory = os.path.dirname(os.path.realpath(__file__))
subdirectory = os.path.join(directory, 'fake', 'fake')
result = steptest.find_project_directory(subdirectory)
assert directory == result


@CauldronTest()
def test_find_failed_at_root(tester: CauldronTest):
def test_find_failed_at_root():
"""Should raise FileNotFoundError if top-level directory has no project"""
directory = os.path.dirname(os.path.realpath(__file__))
subdirectory = os.path.join(directory, 'fake')
Expand All @@ -124,21 +122,18 @@ def test_find_failed_at_root(tester: CauldronTest):
func.assert_called_once_with(subdirectory)


@CauldronTest()
def test_make_temp_path(tester: CauldronTest):
"""Should make a temp path for testing"""
temp_path = tester.make_temp_path('some-id', 'a', 'b.test')
assert temp_path.endswith('b.test')


@CauldronTest()
def test_no_such_step(tester: CauldronTest):
"""Should fail if no such step exists"""
with pytest.raises(Exception):
tester.run_step('FAKE-STEP.no-exists')


@CauldronTest()
def test_no_such_project(tester: CauldronTest):
"""Should fail if no project exists"""
project = cd.project.internal_project
Expand All @@ -150,7 +145,6 @@ def test_no_such_project(tester: CauldronTest):
cd.project.load(project)


@CauldronTest()
def test_open_project_fails(tester: CauldronTest):
"""Should raise Assertion error after failing to open the project"""
with patch('cauldron.steptest.support.open_project') as open_project:
Expand Down

0 comments on commit 442054a

Please sign in to comment.