Skip to content

Commit

Permalink
Merge f0b2bf8 into 6697746
Browse files Browse the repository at this point in the history
  • Loading branch information
miki725 committed Feb 24, 2016
2 parents 6697746 + f0b2bf8 commit b4284b0
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 5 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
56 changes: 55 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,13 @@ 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.'
)

def configure(self, options, conf):
"""
Expand All @@ -110,6 +123,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 +198,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)
95 changes: 91 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

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

self.plugin.configure(mock_options, None)
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,46 @@ 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']

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 = None

self.plugin.startTest(mock_test)

replaced_method = mock_test.test.method
self.assertIsNotNone(replaced_method)
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):
pass

Foo.__module__ = 'foo'

mock_test = mock.MagicMock()
mock_test.test = Foo()
mock_test.test._testMethodName = 'method'
mock_test.test.method = None

self.plugin.startTest(mock_test)

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

0 comments on commit b4284b0

Please sign in to comment.