blob: e72affdb624b20a526b654ce39ccb50506c15af3 [file] [log] [blame]
from tcunittest import TeamcityTestRunner, TeamcityTestResult
from tcmessages import TeamcityServiceMessages
import sys
from pycharm_run_utils import adjust_django_sys_path
adjust_django_sys_path()
from django.conf import settings
if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER:
from nose_utils import TeamcityNoseRunner
from django.test.testcases import TestCase
from django import VERSION
try:
from django.utils import unittest
except ImportError:
import unittest
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")
SUITE_RUNNER = None
BaseSuiteRunner = SUITE_RUNNER or DjangoTestSuiteRunner
class BaseRunner(TeamcityTestRunner, BaseSuiteRunner):
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self, stream)
BaseSuiteRunner.__init__(self, **options)
except ImportError:
# for Django <= 1.1 compatibility
class BaseRunner(TeamcityTestRunner):
def __init__(self, stream=sys.stdout, **options):
TeamcityTestRunner.__init__(self, stream)
def strclass(cls):
if not cls.__name__:
return cls.__module__
return "%s.%s" % (cls.__module__, cls.__name__)
class DjangoTeamcityTestResult(TeamcityTestResult):
def __init__(self, *args, **kwargs):
super(DjangoTeamcityTestResult, self).__init__(**kwargs)
def _getSuite(self, test):
if hasattr(test, "suite"):
suite = strclass(test.suite)
suite_location = test.suite.location
location = test.suite.abs_location
if hasattr(test, "lineno"):
location = location + ":" + str(test.lineno)
else:
location = location + ":" + str(test.test.lineno)
else:
suite = strclass(test.__class__)
suite_location = "django_testid://" + suite
location = "django_testid://" + str(test.id())
return (suite, location, suite_location)
class DjangoTeamcityTestRunner(BaseRunner):
def __init__(self, stream=sys.stdout, **options):
super(DjangoTeamcityTestRunner, self).__init__(stream, **options)
self.options = options
def _makeResult(self, **kwargs):
return DjangoTeamcityTestResult(self.stream, **kwargs)
def build_suite(self, *args, **kwargs):
EXCLUDED_APPS = getattr(settings, 'TEST_EXCLUDE', [])
suite = super(DjangoTeamcityTestRunner, self).build_suite(*args, **kwargs)
if not args[0] and not getattr(settings, 'RUN_ALL_TESTS', False):
tests = []
for case in suite:
pkg = case.__class__.__module__.split('.')[0]
if pkg not in EXCLUDED_APPS:
tests.append(case)
suite._tests = tests
return suite
def run_suite(self, suite, **kwargs):
if hasattr(settings, "TEST_RUNNER") and "NoseTestSuiteRunner" in settings.TEST_RUNNER:
from django_nose.plugin import DjangoSetUpPlugin, ResultPlugin
from django_nose.runner import _get_plugins_from_settings
from nose.config import Config
import nose
result_plugin = ResultPlugin()
plugins_to_add = [DjangoSetUpPlugin(self), result_plugin]
config = Config(plugins=nose.core.DefaultPluginManager())
config.plugins.addPlugins(extraplugins=plugins_to_add)
for plugin in _get_plugins_from_settings():
plugins_to_add.append(plugin)
nose.core.TestProgram(argv=suite, exit=False, addplugins=plugins_to_add,
testRunner=TeamcityNoseRunner(config=config))
return result_plugin.result
else:
self.options.update(kwargs)
return TeamcityTestRunner.run(self, suite, **self.options)
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.
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)
def reorder_suite(suite, classes):
"""
Reorders a test suite by test type.
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]
def run_the_old_way(extra_tests, kwargs, test_labels, verbosity):
from django.test.simple import build_suite, build_test, get_app, get_apps, \
setup_test_environment, teardown_test_environment
setup_test_environment()
settings.DEBUG = False
suite = unittest.TestSuite()
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))
for test in extra_tests:
suite.addTest(test)
suite = reorder_suite(suite, (TestCase,))
old_name = settings.DATABASE_NAME
from django.db import connection
connection.creation.create_test_db(verbosity, autoclobber=False)
result = DjangoTeamcityTestRunner().run(suite, **kwargs)
connection.creation.destroy_test_db(old_name, verbosity)
teardown_test_environment()
return len(result.failures) + len(result.errors)
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.
A list of 'extra' tests may also be provided; these tests
will be added to the test suite.
Returns the number of tests that failed.
"""
options = {
'verbosity': verbosity,
'interactive': interactive
}
options.update(kwargs)
TeamcityServiceMessages(sys.stdout).testMatrixEntered()
if VERSION[1] > 1:
return DjangoTeamcityTestRunner(**options).run_tests(test_labels,
extra_tests=extra_tests, **options)
return run_the_old_way(extra_tests, options, test_labels, verbosity)