Skip to content

Commit 7f98feb

Browse files
danielkzaphobologic
authored andcommitted
Change test runner from nose to py.test (#714)
* Change test runner from nose to py.test Nose has been deprecated by its authors. py.test is very active, widely used, and has many useful features for running and writing tests. Changing the tests themselves away from unittest-style is a different step that must be taken later. This commit only changes the tooling. * dag: port tests to pytest * blueprints: raw: always return absolute template paths Additionaly, adapt tests to not depend on any fixtures in the test directory, or on the current working directory of the test runner. * test: disable deprecation warnings by default due to noise
1 parent 053ad19 commit 7f98feb

File tree

10 files changed

+185
-176
lines changed

10 files changed

+185
-176
lines changed

.gitignore

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,13 @@ dist/
5656
.eggs/
5757
*.egg
5858

59-
# nosetest --with-coverage dumps these in CWD
59+
# Coverage artifacts
6060
.coverage
61-
62-
63-
64-
vm_setup.sh
61+
htmlcov
6562

6663
# Ignore development conf/env files
6764
dev.yaml
6865
dev.env
69-
7066
tests/fixtures/blueprints/*-result
71-
7267
FakeKey.pem
68+
vm_setup.sh

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ lint:
88
flake8 --require-code --min-version=2.7 --ignore FI50,FI51,FI53,FI14,E402,N802,W605 stacker/tests # ignore setUp naming
99

1010
test-unit: clean
11-
python setup.py nosetests
11+
python setup.py test
1212

1313
test-unit3: clean
14-
python3 setup.py nosetests
14+
python3 setup.py test
1515

1616
clean:
1717
rm -rf .egg stacker.egg-info

docs/blueprints.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ structure and execute a test case for it. As an example:
427427
variables:
428428
var1: val1
429429
430-
When run from nosetests, this will create a template fixture file called
430+
When run from tests, this will create a template fixture file called
431431
test_stack.json containing the output from the `stacker_blueprints.s3.Buckets`
432432
template.
433433

setup.cfg

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
[metadata]
22
description-file = README.rst
33

4-
[nosetests]
5-
tests=stacker/tests
6-
detailed-errors=1
7-
with-coverage=1
8-
cover-package=stacker
4+
[aliases]
5+
test = pytest
6+
7+
[tool:pytest]
8+
testpaths = stacker/tests
9+
cov = stacker
10+
filterwarnings =
11+
ignore::DeprecationWarning

setup.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22
from setuptools import setup, find_packages
33

4-
54
VERSION = "1.6.0"
65

76
src_dir = os.path.dirname(__file__)
@@ -20,16 +19,17 @@
2019
"python-dateutil>=2.0,<3.0",
2120
]
2221

22+
setup_requires = ['pytest-runner']
23+
2324
tests_require = [
24-
"mock~=2.0.0",
25+
"pytest~=4.3",
26+
"pytest-cov~=2.6",
27+
"mock~=2.0",
2528
"moto~=1.3.7",
2629
"testfixtures~=4.10.0",
27-
"coverage~=4.3.4",
2830
"flake8-future-import",
2931
]
3032

31-
setup_requires = ["nose"]
32-
3333
scripts = [
3434
"scripts/compare_env",
3535
"scripts/docker-stacker",
@@ -60,7 +60,6 @@ def read(filename):
6060
tests_require=tests_require,
6161
setup_requires=setup_requires,
6262
extras_require=dict(testing=tests_require),
63-
test_suite="nose.collector",
6463
classifiers=[
6564
"Development Status :: 5 - Production/Stable",
6665
"Environment :: Console",

stacker/blueprints/raw.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,11 @@ def get_template_path(filename):
3030
3131
"""
3232
if os.path.isfile(filename):
33-
return filename
33+
return os.path.abspath(filename)
3434
for i in sys.path:
3535
if os.path.isfile(os.path.join(i, filename)):
36-
return os.path.join(i, filename)
36+
return os.path.abspath(os.path.join(i, filename))
37+
3738
return None
3839

3940

stacker/tests/__init__.py

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +0,0 @@
1-
from __future__ import absolute_import, division, print_function
2-
3-
import logging
4-
import os
5-
6-
7-
logger = logging.getLogger(__name__)
8-
_saved_env = {}
9-
10-
11-
def setUpModule():
12-
# Handle change in https://github.com/spulec/moto/issues/1924
13-
# Ensure AWS SDK find some (bogus) credentials in the environment and
14-
# doesn't try to use other providers
15-
overrides = {
16-
'AWS_ACCESS_KEY_ID': 'testing',
17-
'AWS_SECRET_ACCESS_KEY': 'testing',
18-
'AWS_DEFAULT_REGION': 'us-east-1'
19-
}
20-
for key, value in overrides.items():
21-
logger.info('Overriding env var: {}={}'.format(key, value))
22-
_saved_env[key] = os.environ.get(key, None)
23-
os.environ[key] = value
24-
25-
26-
def tearDownModule():
27-
for key, value in _saved_env.items():
28-
logger.info('Restoring saved env var: {}={}'.format(key, value))
29-
if value is None:
30-
del os.environ[key]
31-
else:
32-
os.environ[key] = value
33-
34-
_saved_env.clear()

stacker/tests/blueprints/test_raw.py

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
from __future__ import division
44
from __future__ import absolute_import
55
import json
6-
import os
7-
import sys
86
import unittest
97

108
from mock import MagicMock
@@ -15,66 +13,72 @@
1513
from stacker.variables import Variable
1614
from ..factories import mock_context
1715

16+
1817
RAW_JSON_TEMPLATE_PATH = 'stacker/tests/fixtures/cfn_template.json'
1918
RAW_YAML_TEMPLATE_PATH = 'stacker/tests/fixtures/cfn_template.yaml'
2019
RAW_J2_TEMPLATE_PATH = 'stacker/tests/fixtures/cfn_template.json.j2'
2120

2221

23-
class TestRawBluePrintHelpers(unittest.TestCase):
24-
"""Test class for functions in module."""
25-
26-
def test_get_template_path_local_file(self): # noqa pylint: disable=invalid-name
27-
"""Verify get_template_path finding a file relative to CWD."""
28-
self.assertEqual(get_template_path(RAW_YAML_TEMPLATE_PATH),
29-
RAW_YAML_TEMPLATE_PATH)
30-
31-
def test_get_template_path_invalid_file(self): # noqa pylint: disable=invalid-name
32-
"""Verify get_template_path with an invalid filename."""
33-
self.assertEqual(get_template_path('afilenamethatdoesnotexist.txt'),
34-
None)
35-
36-
def test_get_template_path_file_in_syspath(self): # noqa pylint: disable=invalid-name
37-
"""Verify get_template_path with a file in sys.path.
38-
39-
This ensures templates are able to be retreived from remote packages.
40-
41-
"""
42-
stacker_tests_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) # noqa
43-
old_sys_path = list(sys.path)
44-
sys.path.append(stacker_tests_dir)
45-
try:
46-
self.assertEqual(get_template_path('fixtures/cfn_template.yaml'),
47-
os.path.join(stacker_tests_dir,
48-
'fixtures/cfn_template.yaml'))
49-
finally:
50-
sys.path = old_sys_path
51-
52-
def test_get_template_params(self):
53-
"""Verify get_template_params function operation."""
54-
template_dict = {
55-
"AWSTemplateFormatVersion": "2010-09-09",
56-
"Description": "TestTemplate",
57-
"Parameters": {
58-
"Param1": {
59-
"Type": "String"
60-
},
61-
"Param2": {
62-
"Default": "default",
63-
"Type": "CommaDelimitedList"
64-
}
65-
},
66-
"Resources": {}
67-
}
68-
template_params = {
22+
def test_get_template_path_local_file(tmpdir):
23+
"""Verify get_template_path finding a file relative to CWD."""
24+
25+
template_path = tmpdir.join('cfn_template.json')
26+
template_path.ensure()
27+
28+
with tmpdir.as_cwd():
29+
result = get_template_path('cfn_template.json')
30+
assert template_path.samefile(result)
31+
32+
33+
def test_get_template_path_invalid_file(tmpdir):
34+
"""Verify get_template_path with an invalid filename."""
35+
36+
with tmpdir.as_cwd():
37+
assert get_template_path('cfn_template.json') is None
38+
39+
40+
def test_get_template_path_file_in_syspath(tmpdir, monkeypatch):
41+
"""Verify get_template_path with a file in sys.path.
42+
43+
This ensures templates are able to be retrieved from remote packages.
44+
45+
"""
46+
47+
template_path = tmpdir.join('cfn_template.json')
48+
template_path.ensure()
49+
50+
monkeypatch.syspath_prepend(tmpdir)
51+
result = get_template_path(template_path.basename)
52+
assert template_path.samefile(result)
53+
54+
55+
def test_get_template_params():
56+
"""Verify get_template_params function operation."""
57+
template_dict = {
58+
"AWSTemplateFormatVersion": "2010-09-09",
59+
"Description": "TestTemplate",
60+
"Parameters": {
6961
"Param1": {
7062
"Type": "String"
7163
},
7264
"Param2": {
7365
"Default": "default",
7466
"Type": "CommaDelimitedList"
7567
}
68+
},
69+
"Resources": {}
70+
}
71+
template_params = {
72+
"Param1": {
73+
"Type": "String"
74+
},
75+
"Param2": {
76+
"Default": "default",
77+
"Type": "CommaDelimitedList"
7678
}
77-
self.assertEqual(get_template_params(template_dict), template_params)
79+
}
80+
81+
assert get_template_params(template_dict) == template_params
7882

7983

8084
class TestBlueprintRendering(unittest.TestCase):

stacker/tests/conftest.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from __future__ import absolute_import, division, print_function
2+
3+
import logging
4+
import os
5+
6+
import pytest
7+
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
@pytest.fixture(scope='session', autouse=True)
13+
def aws_credentials():
14+
# Handle change in https://github.com/spulec/moto/issues/1924
15+
# Ensure AWS SDK finds some (bogus) credentials in the environment and
16+
# doesn't try to use other providers.
17+
overrides = {
18+
'AWS_ACCESS_KEY_ID': 'testing',
19+
'AWS_SECRET_ACCESS_KEY': 'testing',
20+
'AWS_DEFAULT_REGION': 'us-east-1'
21+
}
22+
saved_env = {}
23+
for key, value in overrides.items():
24+
logger.info('Overriding env var: {}={}'.format(key, value))
25+
saved_env[key] = os.environ.get(key, None)
26+
os.environ[key] = value
27+
28+
yield
29+
30+
for key, value in saved_env.items():
31+
logger.info('Restoring saved env var: {}={}'.format(key, value))
32+
if value is None:
33+
del os.environ[key]
34+
else:
35+
os.environ[key] = value
36+
37+
saved_env.clear()

0 commit comments

Comments
 (0)