Skip to content

Commit

Permalink
Merge pull request #2 from dealertrack/skip-tests
Browse files Browse the repository at this point in the history
Skip tests
  • Loading branch information
miki725 committed Feb 24, 2016
2 parents 6697746 + 36709d3 commit 710a9bd
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 6 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ script:

after_success:
coveralls

sudo: false
5 changes: 5 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
History
-------

0.2.0 (2016-02-24)
~~~~~~~~~~~~~~~~~~

* **New** added ``--skipnose-skip-tests`` option

0.1.2 (2015-04-29)
~~~~~~~~~~~~~~~~~~

Expand Down
5 changes: 5 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ Plugin adds 3 configuration options to nosetests:
sub2foo3/ <= only this will run
...

``--skipnose-skip-tests``
This option allows to skip specific test cases via json file.
The provided value should be a path to a json file with ``"skip_tests"``
key in json which should contain a list of test case names to skip.

``--skipnose-debug``
This option enabled some extra print statements for debugging
to see which folders skipnose includes or excludes.
Expand Down
2 changes: 1 addition & 1 deletion skipnose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@

__author__ = 'Miroslav Shubernetskiy'
__email__ = '[email protected]'
__version__ = '0.1.2'
__version__ = '0.2.0'
57 changes: 56 additions & 1 deletion skipnose/skipnose.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
from __future__ import unicode_literals, print_function
from __future__ import print_function, unicode_literals
import fnmatch
import functools
import json
import os
import re
import sys

from nose.case import FunctionTestCase
from nose.plugins import Plugin
from nose.plugins.skip import SkipTest


def walk_subfolders(path):
Expand Down Expand Up @@ -39,6 +44,7 @@ def __init__(self):
self.debug = False
self.skipnose_include = None
self.skipnose_exclude = None
self.skipnose_skip_tests = None

def options(self, parser, env=os.environ):
"""
Expand Down Expand Up @@ -92,6 +98,14 @@ def options(self, parser, env=os.environ):
'(alternatively, set ${} as [,;:] delimited string)'
''.format(self.env_exclude_opt)
)
parser.add_option(
'--skipnose-skip-tests',
action='store',
dest='skipnose_skip_tests',
help='skipnose: path to a json file which should contain '
'a list of test method names which should be skipped '
'under "skip_tests" key.'
)

def configure(self, options, conf):
"""
Expand All @@ -110,6 +124,18 @@ def configure(self, options, conf):
self.skipnose_include = options.skipnose_include
self.skipnose_exclude = options.skipnose_exclude

if options.skipnose_skip_tests:
if not os.path.exists(options.skipnose_skip_tests):
print(
'{} not found'.format(options.skipnose_skip_tests),
file=sys.stderr
)
sys.exit(1)

with open(options.skipnose_skip_tests, 'rb') as fid:
data = fid.read().decode('utf-8')
self.skipnose_skip_tests = json.loads(data)['skip_tests']

def wantDirectory(self, dirname):
"""
Nose plugin hook which allows to add logic whether nose
Expand Down Expand Up @@ -173,3 +199,32 @@ def wantDirectory(self, dirname):

# normalize boolean to only ``False`` or ``None``
return False if want is False else None

def startTest(self, test):
"""
Skip tests when skipnose_skip_tests is provided
"""
if not self.skipnose_skip_tests:
return

if isinstance(test.test, FunctionTestCase):
test_name = '{}.{}'.format(
test.test.test.__module__,
test.test.test.__name__,
)
else:
test_name = '{}.{}.{}'.format(
test.test.__class__.__module__,
test.test.__class__.__name__,
test.test._testMethodName,
)

if test_name in self.skipnose_skip_tests:
@functools.wraps(getattr(test.test, test.test._testMethodName))
def skip_test(*args, **kwargs):
raise SkipTest(
'Skipping {!r} as per --skipnose-skip-tests'
''.format(test_name)
)

setattr(test.test, test.test._testMethodName, skip_test)
101 changes: 97 additions & 4 deletions tests/tests_skipnose.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import unicode_literals, print_function
import mock
from __future__ import print_function, unicode_literals
from unittest import TestCase

import mock
from nose.case import FunctionTestCase
from nose.plugins.skip import SkipTest
from skipnose.skipnose import SkipNose, walk_subfolders


Expand Down Expand Up @@ -29,6 +31,7 @@ def test_walk_subfolders(self, mock_walk):
mock_walk.assert_called_once_with('foo')


@mock.patch('skipnose.skipnose.print', mock.MagicMock(), create=True)
class TestSkipNoseConfig(TestCase):
"""
Test class for skipnose configurations
Expand Down Expand Up @@ -77,22 +80,63 @@ def test_options(self):
]
)

def test_configure(self):
@mock.patch('sys.exit')
@mock.patch('os.path.exists')
def test_configure(self, mock_path_exists, mock_sys_exit):
"""
Test that configure sets class attributes correctly
"""
mock_options = mock.MagicMock(
skipnose_debug=mock.sentinel.debug,
skipnose_include=mock.sentinel.include,
skipnose_exclude=mock.sentinel.exclude,
skipnose_skip_tests='foo.json',
)
mock_path_exists.return_value = True
mock_open = mock.MagicMock()
mock_open.return_value.__enter__.return_value.read.return_value = (
b'{"skip_tests": ["one", "two"]}'
)
mock_sys_exit.side_effect = SystemExit

self.plugin.configure(mock_options, None)
with mock.patch('skipnose.skipnose.open', mock_open, create=True):
self.plugin.configure(mock_options, None)

self.assertTrue(self.plugin.enabled)
self.assertEqual(self.plugin.debug, mock.sentinel.debug)
self.assertEqual(self.plugin.skipnose_include, mock.sentinel.include)
self.assertEqual(self.plugin.skipnose_exclude, mock.sentinel.exclude)
self.assertEqual(self.plugin.skipnose_skip_tests, ['one', 'two'])
mock_open.assert_called_once_with('foo.json', 'rb')

@mock.patch('sys.exit')
@mock.patch('os.path.exists')
def test_configure_error(self, mock_path_exists, mock_sys_exit):
"""
Test that configure sets class attributes correctly when
invalid skip-tests path is provided and nose exits
"""
mock_options = mock.MagicMock(
skipnose_debug=mock.sentinel.debug,
skipnose_include=mock.sentinel.include,
skipnose_exclude=mock.sentinel.exclude,
skipnose_skip_tests='foo.data',
)
mock_path_exists.return_value = False
mock_open = mock.MagicMock()
mock_sys_exit.side_effect = SystemExit

with mock.patch('skipnose.skipnose.open', mock_open, create=True):
with self.assertRaises(SystemExit):
self.plugin.configure(mock_options, None)

self.assertTrue(self.plugin.enabled)
self.assertEqual(self.plugin.debug, mock.sentinel.debug)
self.assertEqual(self.plugin.skipnose_include, mock.sentinel.include)
self.assertEqual(self.plugin.skipnose_exclude, mock.sentinel.exclude)
self.assertIsNone(self.plugin.skipnose_skip_tests)
self.assertFalse(mock_open.called)
mock_sys_exit.assert_called_once_with(1)


@mock.patch('skipnose.skipnose.print', mock.MagicMock(), create=True)
Expand Down Expand Up @@ -205,3 +249,52 @@ def test_want_directory_exclude_multiple(self):
actual = self.plugin.wantDirectory(path)
self.assertEqual(actual, expected,
'{} != {} for {}'.format(actual, expected, path))

def test_start_test_no_tests_to_skip(self):
self.plugin.skipnose_skip_tests = None

self.assertIsNone(self.plugin.startTest(mock.Mock()))

def test_start_test_function_test_case(self):
self.plugin.skipnose_skip_tests = ['one', 'two', 'foo.bar']

def test():
""""""

mock_test = mock.MagicMock()
mock_test.test = mock.MagicMock(spec=FunctionTestCase)
mock_test.test.test = mock.MagicMock(__module__='foo', __name__='bar')
mock_test.test._testMethodName = 'method'
mock_test.test.method = test

self.plugin.startTest(mock_test)

replaced_method = mock_test.test.method
self.assertIsNot(replaced_method, test)
self.assertTrue(callable(replaced_method))
with self.assertRaises(SkipTest):
replaced_method()

def test_start_test_method_test_case(self):
self.plugin.skipnose_skip_tests = ['one', 'two', 'foo.Foo.method']

class Foo(object):
def method(self):
""""""

Foo.__module__ = 'foo'
instance = Foo()
test = instance.method

mock_test = mock.MagicMock()
mock_test.test = instance
mock_test.test._testMethodName = 'method'
mock_test.test.method = test

self.plugin.startTest(mock_test)

replaced_method = mock_test.test.method
self.assertIsNot(replaced_method, test)
self.assertTrue(callable(replaced_method))
with self.assertRaises(SkipTest):
replaced_method()

0 comments on commit 710a9bd

Please sign in to comment.