Skip to content

Instantly share code, notes, and snippets.

@mattvonrocketstein
Created September 23, 2013 22:59
Show Gist options
  • Select an option

  • Save mattvonrocketstein/6678175 to your computer and use it in GitHub Desktop.

Select an option

Save mattvonrocketstein/6678175 to your computer and use it in GitHub Desktop.
partition tests by type, retrieve misc. test metadata
import os, sys
import inspect
import unittest, unittest2
from django import test as dtest
import nose
def _suite2list(s):
return [x for x in _suite2iter(s)]
def _suite2iter(s):
""" suites contain tests but also *are* tests
so unpacking them takes some effort.
"""
for test in s:
if unittest.suite._isnotsuite(test):
yield test
else:
for t in _suite2iter(test):
yield t
class2dotpath = lambda x: "{0}.{1}".format(x.__module__, x.__name__)
class PartionTestsByType(nose.core.TestProgram):
_suite2list = staticmethod(_suite2list)
def _dammit_nose_you_took_my_io(self):
""" NB: without this prints and embedded
shells will not be possible """
sys.stdout = sys.__stdout__
sys.stdin = sys.__stdin__
def consider_test(self, test):
## handed some kind of nose wrapper at first, unpack it
unwrapped_test = test.test
## almost got something useful.. unpack more metadata
test_class = unwrapped_test.__class__
test_method_name = unwrapped_test._testMethodName
bound_test_method = getattr(unwrapped_test, test_method_name)
test_method_source = inspect.getsource(bound_test_method)
setUp_method_source = inspect.getsource(test_class.setUp)
## things we know for sure
test_class_bases = test_class.__bases__
test_class_base_names = [ class2dotpath(x) for x in test_class_bases]
is_unittest2 = unittest2.TestCase in test_class_bases
is_unittest1 = unittest.TestCase in test_class_bases
is_django_testcase = any([
# FIXME: there's a bug here since this should be truly recursive
issubclass(x, dtest.TransactionTestCase ) \
for x in test_class_bases])
is_using_django_fixtures = is_django_testcase and \
bool(getattr(test_class, 'fixtures', []))
#
# TODO:
# is_solr_integration_test = ...
#
# this can't work with issubclass() because for instance when
# partitioning tests in some random component, we wont be able
# to import medley.abc.testing.HaystackTestCase. will have to
# use kls.__name__ (and dont forget to recurse up thru parent
# classes properly.)
#
# heuristics (but pretty strong ones, imho)
using_django_test_client = 'self.client.' in test_method_source
method_needs_refactor = len(test_method_source.split('\n')) > 8
class_needs_refactor = any([
# setup method too long?
len(setUp_method_source.split('\n')) > 10,
# too many methods?
len([x for x in dir(test_class) if x.startswith('test_')])])
result = locals()
result.pop('self')
return result
def runTests(self):
""" we don't really want to run tests;
we want to inspect them. this is a nice
place to hook in though because we know
the suite is fully collected and prepared
"""
self._dammit_nose_you_took_my_io()
every_test = _suite2list(self.test) # [ nose.case.Test, .. ]
for test in every_test:
print 'considering: ', test
partition = self.consider_test(test)
#
# do something with partition data here
#
#
# do any aggregating necessary for reporting here.
# for now we just drop to a shell here, so the user can
# inspect the last test we considered.
#
# (..try typing "print partition" from the terminal)
#
from IPython import Shell; Shell.IPShellEmbed(argv=['-noconfirm_exit'])()
#return True # just to be safe. probably used for the sys.exit() status.
if __name__ == '__main__':
PartionTestsByType(argv=['-w', '.', '--collect'],)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment