Login

Fail Faster: unsafe_test Management Command

Author:
majgis
Posted:
August 10, 2012
Language:
Python
Version:
1.4
Tags:
management-command
Score:
0 (after 0 ratings)

The faster you fail the faster you reach success. This management command runs tests within the django environment, but without a test database, hence the word "UNSAFE". It only runs unittests for a single application, which are not subclasses of django.test.TestCase. Django's TestCases are not supported because they attempt to purge the database. Turn this flaw into a feature by segregating testcases into those that either need or don't need the test database. This tool may not be useful in all cases, but in certain cases you can have more rapid testing iterations. I use it for certain utility applications.

Setup:

Place in <app_name>/management/commands/unsafe_test.py

Run:

$./manage.py unsafe_test <app_name>

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.test import TestCase as django_TestCase
import importlib
import unittest

class Command(BaseCommand):
  """ Command for running quick tests without a separate test database.
  
    Subclasses of django.test.Testcase are not supported since they attempt to 
    flush the database.
    
  """

  args = '<application name>'
  help = 'Run unittests for specified application without creating test \
database. Subclasses of django.test.TestCase are not supported.'
  
  INVALED_APP_MSG = 'The first argument must be a valid application name'
  NO_TESTS_MSG = 'No tests.py file was found in the application you specified'

  def handle(self, *args, **kwargs):
    """ Required for management command
    """
    
    if len(args) == 0:
      raise CommandError(self.INVALED_APP_MSG)
    
    app_name = args[0]
    
    self.TestApp(app_name)
    
  
  def TestApp(self, app_name):
    """Run tests for the specified application."""
    
    if not app_name in settings.INSTALLED_APPS:
      raise CommandError(self.INVALED_APP_MSG)
    
    try:
      tests = importlib.import_module('.'.join([app_name, 'tests']))
    except:
      raise CommandError(self.NO_TESTS_MSG)
    
    suite = self.LoadNonJangoTestsFromModule(tests)
    
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)   
    
    return result
  
  def LoadNonJangoTestsFromModule(self, module):
    """ Load tests from module which are not subclass of django.test.TestCase
    """
    
    tests = []
    loader = unittest.TestLoader()
    for name in dir(module):
      obj = getattr(module, name)
      
      if isinstance(obj, type)\
      and issubclass(obj, unittest.TestCase)\
      and not issubclass(obj, django_TestCase):
        tests += loader.loadTestsFromTestCase(obj)
    
    return unittest.TestSuite(tests)

More like this

  1. Exclude Apps When Testing by cronosa 4 years, 7 months ago
  2. "Zoom in" on rendered HTML that the test client returns by peterbe 6 years, 1 month ago
  3. Link Media Command by elwaywitvac 6 years, 8 months ago
  4. Continuous Integration command by berto 5 years, 7 months ago
  5. Test Django against many Pythons and databases by jacobian 8 years, 2 months ago

Comments

Please login first before commenting.