fixed nose in django with nose plugin

This commit is contained in:
Ekaterina Tuzova
2013-01-09 13:11:55 +04:00
parent e9542398e6
commit bce962d70f
2 changed files with 177 additions and 92 deletions
+95 -78
View File
@@ -9,35 +9,39 @@ import sys
def get_test_suite_runner():
if hasattr(settings, "TEST_RUNNER"):
from django.test.utils import get_runner
class TempSettings:
TEST_RUNNER = settings.TEST_RUNNER
return get_runner(TempSettings)
try:
from django.test.simple import DjangoTestSuiteRunner
from inspect import isfunction
SUITE_RUNNER = get_test_suite_runner()
if isfunction(SUITE_RUNNER):
import sys
sys.stderr.write("WARNING: TEST_RUNNER variable is ignored. PyCharm test runner supports "
"only class-like TEST_RUNNER valiables. Use Tools->run manage.py tasks.\n")
sys.stderr.write(
"WARNING: TEST_RUNNER variable is ignored. PyCharm test runner supports "
"only class-like TEST_RUNNER valiables. Use Tools->run manage.py tasks.\n")
SUITE_RUNNER = None
BaseSuiteRunner = SUITE_RUNNER or DjangoTestSuiteRunner
class BaseRunner(TeamcityTestRunner, BaseSuiteRunner):
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self,stream)
TeamcityTestRunner.__init__(self, stream)
BaseSuiteRunner.__init__(self)
except ImportError:
class BaseRunner(TeamcityTestRunner):
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self,stream)
TeamcityTestRunner.__init__(self, stream)
class DjangoTeamcityTestRunner(BaseRunner):
def __init__(self, stream=sys.stdout, **options):
BaseRunner.__init__(self, stream)
#self.interactive = False
super(DjangoTeamcityTestRunner, self).__init__(stream)
def build_suite(self, *args, **kwargs):
EXCLUDED_APPS = getattr(settings, 'TEST_EXCLUDE', [])
@@ -69,100 +73,113 @@ class DjangoTeamcityTestRunner(BaseRunner):
from nose_utils import TeamcityNoseRunner
nose.core.TestProgram(argv=suite, exit=False, testRunner=TeamcityNoseRunner(config=config))
nose.core.TestProgram(argv=suite, exit=False,
testRunner=TeamcityNoseRunner(config=config))
return result_plugin.result
else:
return TeamcityTestRunner.run(self, suite, **kwargs)
def run_tests(self, test_labels, extra_tests=None, **kwargs):
if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER:
return super(DjangoTeamcityTestRunner, self).run_tests(test_labels,
extra_tests)
return super(DjangoTeamcityTestRunner, self).run_tests(test_labels,
extra_tests, **kwargs)
def partition_suite(suite, classes, bins):
"""
Partitions a test suite by test type.
"""
Partitions a test suite by test type.
classes is a sequence of types
bins is a sequence of TestSuites, one more than classes
classes is a sequence of types
bins is a sequence of TestSuites, one more than classes
Tests of type classes[i] are added to bins[i],
tests with no match found in classes are place in bins[-1]
"""
for test in suite:
if isinstance(test, unittest.TestSuite):
partition_suite(test, classes, bins)
else:
for i in range(len(classes)):
if isinstance(test, classes[i]):
bins[i].addTest(test)
break
else:
bins[-1].addTest(test)
Tests of type classes[i] are added to bins[i],
tests with no match found in classes are place in bins[-1]
"""
for test in suite:
if isinstance(test, unittest.TestSuite):
partition_suite(test, classes, bins)
else:
for i in range(len(classes)):
if isinstance(test, classes[i]):
bins[i].addTest(test)
break
else:
bins[-1].addTest(test)
def reorder_suite(suite, classes):
"""
Reorders a test suite by test type.
"""
Reorders a test suite by test type.
classes is a sequence of types
classes is a sequence of types
All tests of type clases[0] are placed first, then tests of type classes[1], etc.
Tests with no match in classes are placed last.
"""
class_count = len(classes)
bins = [unittest.TestSuite() for i in range(class_count+1)]
partition_suite(suite, classes, bins)
for i in range(class_count):
bins[0].addTests(bins[i+1])
return bins[0]
All tests of type clases[0] are placed first, then tests of type classes[1], etc.
Tests with no match in classes are placed last.
"""
class_count = len(classes)
bins = [unittest.TestSuite() for i in range(class_count + 1)]
partition_suite(suite, classes, bins)
for i in range(class_count):
bins[0].addTests(bins[i + 1])
return bins[0]
def run_tests(test_labels, verbosity=1, interactive=False, extra_tests=[], **kwargs):
"""
Run the unit tests for all the test labels in the provided list.
Labels must be of the form:
- app.TestClass.test_method
Run a single specific test method
- app.TestClass
Run all the test methods in a given class
- app
Search for doctests and unittests in the named application.
When looking for tests, the test runner will look in the models and
tests modules for the application.
def run_tests(test_labels, verbosity=1, interactive=False, extra_tests=[],
**kwargs):
"""
Run the unit tests for all the test labels in the provided list.
Labels must be of the form:
- app.TestClass.test_method
Run a single specific test method
- app.TestClass
Run all the test methods in a given class
- app
Search for doctests and unittests in the named application.
A list of 'extra' tests may also be provided; these tests
will be added to the test suite.
When looking for tests, the test runner will look in the models and
tests modules for the application.
Returns the number of tests that failed.
"""
TeamcityServiceMessages(sys.stdout).testMatrixEntered()
if django.VERSION[1] > 1:
return DjangoTeamcityTestRunner().run_tests(test_labels, extra_tests=extra_tests, **kwargs)
A list of 'extra' tests may also be provided; these tests
will be added to the test suite.
setup_test_environment()
Returns the number of tests that failed.
"""
TeamcityServiceMessages(sys.stdout).testMatrixEntered()
if django.VERSION[1] > 1:
return DjangoTeamcityTestRunner().run_tests(test_labels,
extra_tests=extra_tests, **kwargs)
settings.DEBUG = False
suite = unittest.TestSuite()
setup_test_environment()
if test_labels:
for label in test_labels:
if '.' in label:
suite.addTest(build_test(label))
else:
app = get_app(label)
suite.addTest(build_suite(app))
else:
for app in get_apps():
suite.addTest(build_suite(app))
settings.DEBUG = False
suite = unittest.TestSuite()
for test in extra_tests:
suite.addTest(test)
if test_labels:
for label in test_labels:
if '.' in label:
suite.addTest(build_test(label))
else:
app = get_app(label)
suite.addTest(build_suite(app))
else:
for app in get_apps():
suite.addTest(build_suite(app))
suite = reorder_suite(suite, (TestCase,))
for test in extra_tests:
suite.addTest(test)
old_name = settings.DATABASE_NAME
from django.db import connection
connection.creation.create_test_db(verbosity, autoclobber=False)
suite = reorder_suite(suite, (TestCase,))
result = DjangoTeamcityTestRunner().run(suite, **kwargs)
connection.creation.destroy_test_db(old_name, verbosity)
old_name = settings.DATABASE_NAME
from django.db import connection
teardown_test_environment()
connection.creation.create_test_db(verbosity, autoclobber=False)
return len(result.failures) + len(result.errors)
result = DjangoTeamcityTestRunner().run(suite, **kwargs)
connection.creation.destroy_test_db(old_name, verbosity)
teardown_test_environment()
return len(result.failures) + len(result.errors)
+82 -14
View File
@@ -1,27 +1,45 @@
from tcmessages import TeamcityServiceMessages
import sys, traceback, datetime
import unittest
from tcunittest import strclass
from tcunittest import TeamcityTestResult
try:
from nose.util import isclass # backwards compat
from nose.plugins.base import Plugin
from nose.config import Config
from nose.result import TextTestResult
except (Exception, ):
e = sys.exc_info()[1]
raise NameError("Something went wrong, do you have nosetest installed? I got this error: %s" % e)
raise NameError(
"Something went wrong, do you have nosetest installed? I got this error: %s" % e)
class TeamcityPlugin(Plugin):
class TeamcityPlugin(Plugin, TextTestResult, TeamcityTestResult):
"""
TeamcityTest plugin for nose tests
"""
name = "TeamcityPlugin"
enabled = True
def __init__(self):
self.messages = TeamcityServiceMessages(sys.stderr, prepend_linebreak=True)
self.messages.testMatrixEntered()
self.current_suite = None
def __init__(self, stream=sys.stderr, descriptions=None, verbosity=1,
config=None, errorClasses=None):
super(TeamcityPlugin, self).__init__()
if errorClasses is None:
errorClasses = {}
self.errorClasses = errorClasses
if config is None:
config = Config()
self.config = config
self.output = stream
self.messages = TeamcityServiceMessages(self.output,
prepend_linebreak=True)
self.messages.testMatrixEntered()
self.current_suite = None
TextTestResult.__init__(self, stream, descriptions, verbosity, config,
errorClasses)
TeamcityTestResult.__init__(self, stream)
def configure(self, options, conf):
if not self.can_configure:
@@ -32,7 +50,7 @@ class TeamcityPlugin(Plugin):
def addError(self, test, err):
err = self.formatErr(err)
self.messages.testError(self.getTestName(test),
message='Error', details=err)
message='Error', details=err)
def formatErr(self, err):
@@ -66,7 +84,7 @@ class TeamcityPlugin(Plugin):
err = self.formatErr(err)
self.messages.testFailed(self.getTestName(test),
message='Failure', details=err)
message='Failure', details=err)
def addSkip(self, test, reason):
@@ -89,11 +107,15 @@ class TeamcityPlugin(Plugin):
from nose_helper.util import func_lineno
if hasattr(test.test, "descriptor") and test.test.descriptor:
suite_location = "file://" + self.test_address(test.test.descriptor)
location = suite_location + ":" + str(func_lineno(test.test.descriptor))
suite_location = "file://" + self.test_address(
test.test.descriptor)
location = suite_location + ":" + str(
func_lineno(test.test.descriptor))
else:
suite_location = "file://" + self.test_address(test.test.test)
location = "file://" + self.test_address(test.test.test) + ":" + str(func_lineno(test.test.test))
suite_location = "file://" + self.test_address(
test.test.test)
location = "file://" + self.test_address(
test.test.test) + ":" + str(func_lineno(test.test.test))
except:
test_id = test.id()
suite_id = test_id[:test_id.rfind(".")]
@@ -149,7 +171,8 @@ class TeamcityPlugin(Plugin):
if self.current_suite:
self.messages.testSuiteFinished(self.current_suite)
self.current_suite = suite
self.messages.testSuiteStarted(self.current_suite, location=suite_location)
self.messages.testSuiteStarted(self.current_suite,
location=suite_location)
setattr(test, "startTime", datetime.datetime.now())
self.messages.testStarted(self.getTestName(test), location=location)
@@ -158,10 +181,55 @@ class TeamcityPlugin(Plugin):
start = getattr(test, "startTime", datetime.datetime.now())
d = datetime.datetime.now() - start
duration = d.microseconds / 1000 + d.seconds * 1000 + d.days * 86400000
self.messages.testFinished(self.getTestName(test), duration=int(duration))
self.messages.testFinished(self.getTestName(test),
duration=int(duration))
def finalize(self, result):
if self.current_suite:
self.messages.testSuiteFinished(self.current_suite)
self.current_suite = None
class TeamcityNoseRunner(unittest.TextTestRunner):
"""Test runner that supports teamcity output
"""
def __init__(self, stream=sys.stdout, descriptions=1, verbosity=1,
config=None):
if config is None:
config = Config()
self.config = config
unittest.TextTestRunner.__init__(self, stream, descriptions, verbosity)
def _makeResult(self):
return TeamcityPlugin(self.stream,
self.descriptions,
self.verbosity,
self.config)
def run(self, test):
"""Overrides to provide plugin hooks and defer all output to
the test result class.
"""
#for 2.5 compat
plugins = self.config.plugins
plugins.configure(self.config.options, self.config)
plugins.begin()
wrapper = plugins.prepareTest(test)
if wrapper is not None:
test = wrapper
# plugins can decorate or capture the output stream
wrapped = self.config.plugins.setOutputStream(self.stream)
if wrapped is not None:
self.stream = wrapped
result = self._makeResult()
test(result)
result.endLastSuite()
plugins.finalize(result)
return result