Login

Fail Faster: unsafe_test Management Command

Author:
majgis
Posted:
August 10, 2012
Language:
Python
Version:
1.4
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. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

Please login first before commenting.