diff --git a/.gitignore b/.gitignore
index 99daac5ca8151642fcea430d5a36fa42a1f987e1..05c992e3f9ddc3fb38323fbdc356c996822989a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -58,3 +58,5 @@ Debug
 *_out.tab
 *_out.pickle
 /modules/io/tests/temp_img.tmp
+PYTEST-*.xml
+ost_*_tests_log.xml
diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake
index c0d021624494e82596924dc5ca4c7591b775e2f9..7cfd989921755285d2da663bdce0f6041c10f569 100644
--- a/cmake_support/OST.cmake
+++ b/cmake_support/OST.cmake
@@ -596,6 +596,7 @@ macro(pymod)
 endmacro()
 
 add_custom_target(check)
+add_custom_target(check_xml)
 if (WIN32)
   set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL "1")
 endif()
@@ -640,7 +641,12 @@ macro(ost_unittest)
         target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES}
                             "${_ARG_PREFIX}_${_ARG_MODULE}")
         add_custom_target("${_test_name}_run"
-                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo 
+                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo
+                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                        COMMENT "running checks for module ${_ARG_MODULE}"
+                        DEPENDS ${_test_name})
+        add_custom_target("${_test_name}_run_xml"
+                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} --log_format=xml --log_level=all > ${_test_name}_log.xml || echo
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                         COMMENT "running checks for module ${_ARG_MODULE}"
                         DEPENDS ${_test_name})
@@ -652,6 +658,7 @@ macro(ost_unittest)
       endif()
 
       add_dependencies(check "${_test_name}_run")
+      add_dependencies(check_xml "${_test_name}_run_xml")
       set_target_properties(${_test_name}
                             PROPERTIES RUNTIME_OUTPUT_DIRECTORY
                             "${CMAKE_CURRENT_BINARY_DIR}")
@@ -672,9 +679,15 @@ macro(ost_unittest)
                   sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo"
                   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                   COMMENT "running checks ${py_test}" VERBATIM)
+        add_custom_target("${py_test}_run_xml"
+                  sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} xml || echo"
+                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                  COMMENT "running checks ${py_test}" VERBATIM)
       endif()
       add_dependencies("${py_test}_run" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
+      add_dependencies("${py_test}_run_xml" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
       add_dependencies(check "${py_test}_run")
+      add_dependencies(check_xml "${py_test}_run_xml")
       if (WIN32)
         set_target_properties("${py_test}_run" PROPERTIES EXCLUDE_FROM_ALL "1")
       endif()
diff --git a/modules/base/doc/base.rst b/modules/base/doc/base.rst
index 6e0a6caf5f16b2367498e4284a98a1f067be92dd..72d9ed9dcc547e63247afb10905942c1be04a8b0 100644
--- a/modules/base/doc/base.rst
+++ b/modules/base/doc/base.rst
@@ -5,3 +5,4 @@
 
   logging
   settings
+  testutils
diff --git a/modules/base/doc/testutils.rst b/modules/base/doc/testutils.rst
new file mode 100644
index 0000000000000000000000000000000000000000..649a0b3b350a2b30866f98a11873672acefdc5fa
--- /dev/null
+++ b/modules/base/doc/testutils.rst
@@ -0,0 +1,7 @@
+:mod:`~ost.testutils` -- Utils for Running Python Unittests
+================================================================================
+
+.. module:: ost.testutils
+  :synopsis: Helper Functions to Run Python Unittests
+
+.. autofunction:: ost.testutils.RunTests
\ No newline at end of file
diff --git a/modules/base/pymod/CMakeLists.txt b/modules/base/pymod/CMakeLists.txt
index 3f4f748a509f9e43796cb4bde0edf2c5cc162fc8..0e9213ba1cb9795b86e212c36d4e0fa8cc20fe92 100644
--- a/modules/base/pymod/CMakeLists.txt
+++ b/modules/base/pymod/CMakeLists.txt
@@ -7,4 +7,4 @@ set(OST_BASE_PYMOD_SOURCES
 
 pymod(NAME base OUTPUT_DIR ost 
       CPP ${OST_BASE_PYMOD_SOURCES} 
-      PY __init__.py settings.py stutil.py table.py)
+      PY __init__.py settings.py stutil.py table.py xmlrunner.py testutils.py)
diff --git a/modules/base/pymod/testutils.py b/modules/base/pymod/testutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe3e7a024d0c19baea30fa663549f5513489870a
--- /dev/null
+++ b/modules/base/pymod/testutils.py
@@ -0,0 +1,54 @@
+def RunTests():
+  '''
+  This function behaves as a custom TestLoader for python unittests.
+
+  With no system arguments, the default unittest TestRunner is used.
+
+  If the first system argument (sys.argv[1]) is set to 'xml', a XMLTestRunner
+  is used, which produces a JUnit compatible XML output file. Within the current
+  module, each function is identified which is a subclass of unittest.TestCase
+  and for each TestCase, a test suite is executed, producing an individual
+  output file for each TestCase. The output file has the name,
+  'PYTEST-<TestCaseName>.xml'.
+
+  Example of a Python testcase:
+
+  .. code-block:: python
+
+    import unittest
+
+    class TestRenumber(unittest.TestCase):
+
+      def setUp(self):
+        # prepare stuff"
+        pass
+
+      def testSomeFunction(self):
+        # do some asserts
+        pass
+
+    if __name__ == "__main__":
+      from ost import testutils
+      testutils.RunTests()
+
+  '''
+  import unittest
+  import sys
+  try:
+    if len(sys.argv)>1 and sys.argv[1]=='xml':
+      import inspect
+      import types
+      import __main__
+      from ost import xmlrunner
+      for name, obj in inspect.getmembers(__main__):
+        if (isinstance(obj, (type, types.ClassType)) and
+                            issubclass(obj, unittest.TestCase)):
+          suite = unittest.TestLoader().loadTestsFromTestCase(obj)
+          stream = open('PYTEST-%s.xml'%name, 'w')
+          xmlrunner.XMLTestRunner(stream).run(suite)
+          stream.close()
+
+    else:
+      unittest.main()
+  except Exception, e:
+    print e
\ No newline at end of file
diff --git a/modules/base/pymod/xmlrunner.py b/modules/base/pymod/xmlrunner.py
new file mode 100644
index 0000000000000000000000000000000000000000..86c10b3f9bd84f7e47c46b717f0ed8c0038397dc
--- /dev/null
+++ b/modules/base/pymod/xmlrunner.py
@@ -0,0 +1,384 @@
+"""
+XML Test Runner for PyUnit
+"""
+
+# Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
+# the Public Domain. With contributions by Paolo Borelli and others.
+
+from __future__ import with_statement
+
+__version__ = "0.1"
+
+import os.path
+import re
+import sys
+import time
+import traceback
+import unittest
+from xml.sax.saxutils import escape
+
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
+
+
+class _TestInfo(object):
+
+    """Information about a particular test.
+
+    Used by _XMLTestResult.
+
+    """
+
+    def __init__(self, test, time):
+        (self._class, self._method) = test.id().rsplit(".", 1)
+        self._time = time
+        self._error = None
+        self._failure = None
+
+    @staticmethod
+    def create_success(test, time):
+        """Create a _TestInfo instance for a successful test."""
+        return _TestInfo(test, time)
+
+    @staticmethod
+    def create_failure(test, time, failure):
+        """Create a _TestInfo instance for a failed test."""
+        info = _TestInfo(test, time)
+        info._failure = failure
+        return info
+
+    @staticmethod
+    def create_error(test, time, error):
+        """Create a _TestInfo instance for an erroneous test."""
+        info = _TestInfo(test, time)
+        info._error = error
+        return info
+
+    def print_report(self, stream):
+        """Print information about this test case in XML format to the
+        supplied stream.
+
+        """
+        stream.write('  <testcase classname="%(class)s" name="%(method)s" time="%(time).4f">' % \
+            {
+                "class": self._class,
+                "method": self._method,
+                "time": self._time,
+            })
+        if self._failure is not None:
+            self._print_error(stream, 'failure', self._failure)
+        if self._error is not None:
+            self._print_error(stream, 'error', self._error)
+        stream.write('</testcase>\n')
+
+    def _print_error(self, stream, tagname, error):
+        """Print information from a failure or error to the supplied stream."""
+        text = escape(str(error[1]))
+        stream.write('\n')
+        stream.write('    <%s type="%s">%s\n' \
+            % (tagname, _clsname(error[0]), text))
+        tb_stream = StringIO()
+        traceback.print_tb(error[2], None, tb_stream)
+        stream.write(escape(tb_stream.getvalue()))
+        stream.write('    </%s>\n' % tagname)
+        stream.write('  ')
+
+
+def _clsname(cls):
+    return cls.__module__ + "." + cls.__name__
+
+
+class _XMLTestResult(unittest.TestResult):
+
+    """A test result class that stores result as XML.
+
+    Used by XMLTestRunner.
+
+    """
+
+    def __init__(self, classname):
+        unittest.TestResult.__init__(self)
+        self._test_name = classname
+        self._start_time = None
+        self._tests = []
+        self._error = None
+        self._failure = None
+
+    def startTest(self, test):
+        unittest.TestResult.startTest(self, test)
+        self._error = None
+        self._failure = None
+        self._start_time = time.time()
+
+    def stopTest(self, test):
+        time_taken = time.time() - self._start_time
+        unittest.TestResult.stopTest(self, test)
+        if self._error:
+            info = _TestInfo.create_error(test, time_taken, self._error)
+        elif self._failure:
+            info = _TestInfo.create_failure(test, time_taken, self._failure)
+        else:
+            info = _TestInfo.create_success(test, time_taken)
+        self._tests.append(info)
+
+    def addError(self, test, err):
+        unittest.TestResult.addError(self, test, err)
+        self._error = err
+
+    def addFailure(self, test, err):
+        unittest.TestResult.addFailure(self, test, err)
+        self._failure = err
+
+    def print_report(self, stream, time_taken, out, err):
+        """Prints the XML report to the supplied stream.
+
+        The time the tests took to perform as well as the captured standard
+        output and standard error streams must be passed in.a
+
+        """
+        stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' % \
+            { "e": len(self.errors), "f": len(self.failures) })
+        stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % \
+            {
+                "n": self._test_name,
+                "t": self.testsRun,
+                "time": time_taken,
+            })
+        for info in self._tests:
+            info.print_report(stream)
+        stream.write('  <system-out><![CDATA[%s]]></system-out>\n' % out)
+        stream.write('  <system-err><![CDATA[%s]]></system-err>\n' % err)
+        stream.write('</testsuite>\n')
+
+
+class XMLTestRunner(object):
+
+    """A test runner that stores results in XML format compatible with JUnit.
+
+    XMLTestRunner(stream=None) -> XML test runner
+
+    The XML file is written to the supplied stream. If stream is None, the
+    results are stored in a file called TEST-<module>.<class>.xml in the
+    current working directory (if not overridden with the path property),
+    where <module> and <class> are the module and class name of the test class.
+
+    """
+
+    def __init__(self, stream=None):
+        self._stream = stream
+        self._path = "."
+
+    def run(self, test):
+        """Run the given test case or test suite."""
+        class_ = test.__class__
+        classname = class_.__module__ + "." + class_.__name__
+        if self._stream == None:
+            filename = "TEST-%s.xml" % classname
+            stream = file(os.path.join(self._path, filename), "w")
+            stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
+        else:
+            stream = self._stream
+
+        result = _XMLTestResult(classname)
+        start_time = time.time()
+
+        with _fake_std_streams():
+            test(result)
+            try:
+                out_s = sys.stdout.getvalue()
+            except AttributeError:
+                out_s = ""
+            try:
+                err_s = sys.stderr.getvalue()
+            except AttributeError:
+                err_s = ""
+
+        time_taken = time.time() - start_time
+        result.print_report(stream, time_taken, out_s, err_s)
+        if self._stream is None:
+            stream.close()
+
+        return result
+
+    def _set_path(self, path):
+        self._path = path
+
+    path = property(lambda self: self._path, _set_path, None,
+            """The path where the XML files are stored.
+
+            This property is ignored when the XML file is written to a file
+            stream.""")
+
+
+class _fake_std_streams(object):
+
+    def __enter__(self):
+        self._orig_stdout = sys.stdout
+        self._orig_stderr = sys.stderr
+        sys.stdout = StringIO()
+        sys.stderr = StringIO()
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        sys.stdout = self._orig_stdout
+        sys.stderr = self._orig_stderr
+
+
+class XMLTestRunnerTest(unittest.TestCase):
+
+    def setUp(self):
+        self._stream = StringIO()
+
+    def _try_test_run(self, test_class, expected):
+
+        """Run the test suite against the supplied test class and compare the
+        XML result against the expected XML string. Fail if the expected
+        string doesn't match the actual string. All time attributes in the
+        expected string should have the value "0.000". All error and failure
+        messages are reduced to "Foobar".
+
+        """
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(test_class))
+
+        got = self._stream.getvalue()
+        # Replace all time="X.YYY" attributes by time="0.000" to enable a
+        # simple string comparison.
+        got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
+        # Likewise, replace all failure and error messages by a simple "Foobar"
+        # string.
+        got = re.sub(r'(?s)<failure (.*?)>.*?</failure>', r'<failure \1>Foobar</failure>', got)
+        got = re.sub(r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
+        # And finally Python 3 compatibility.
+        got = got.replace('type="builtins.', 'type="exceptions.')
+
+        self.assertEqual(expected, got)
+
+    def test_no_tests(self):
+        """Regression test: Check whether a test run without any tests
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            pass
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_success(self):
+        """Regression test: Check whether a test run with a successful test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                pass
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_failure(self):
+        """Regression test: Check whether a test run with a failing test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                self.assert_(False)
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+    <failure type="exceptions.AssertionError">Foobar</failure>
+  </testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_error(self):
+        """Regression test: Check whether a test run with a erroneous test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                raise IndexError()
+        self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+    <error type="exceptions.IndexError">Foobar</error>
+  </testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_stdout_capture(self):
+        """Regression test: Check whether a test run with output to stdout
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stdout.write("Test\n")
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[Test
+]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_stderr_capture(self):
+        """Regression test: Check whether a test run with output to stderr
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stderr.write("Test\n")
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[Test
+]]></system-err>
+</testsuite>
+""")
+
+    class NullStream(object):
+        """A file-like object that discards everything written to it."""
+        def write(self, buffer):
+            pass
+
+    def test_unittests_changing_stdout(self):
+        """Check whether the XMLTestRunner recovers gracefully from unit tests
+        that change stdout, but don't change it back properly.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stdout = XMLTestRunnerTest.NullStream()
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(TestTest))
+
+    def test_unittests_changing_stderr(self):
+        """Check whether the XMLTestRunner recovers gracefully from unit tests
+        that change stderr, but don't change it back properly.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stderr = XMLTestRunnerTest.NullStream()
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(TestTest))
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/modules/base/tests/test_log.py b/modules/base/tests/test_log.py
index 9b6952c912dc28f6252360ea8c5e9f5a4879b189..cec9378edc965174e460c392ee8bf28a69d106e8 100644
--- a/modules/base/tests/test_log.py
+++ b/modules/base/tests/test_log.py
@@ -39,7 +39,5 @@ class TestLog(unittest.TestCase):
     self.assertEqual(ls.severity, 1)
     ost.PopLogSink()
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
\ No newline at end of file
+  from ost import testutils
+  testutils.RunTests()
\ No newline at end of file
diff --git a/modules/base/tests/test_stutil.py b/modules/base/tests/test_stutil.py
index 6cc4570b5605b5eb47c7507e0d0aa7f942f66496..7d5b9f98f9790db63846bfaa934fafa7de1d891b 100644
--- a/modules/base/tests/test_stutil.py
+++ b/modules/base/tests/test_stutil.py
@@ -86,7 +86,5 @@ class TestStUtils(unittest.TestCase):
            (stutil.Correl(self.data3, self.data2), self.correl2)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
\ No newline at end of file
+  from ost import testutils
+  testutils.RunTests()
\ No newline at end of file
diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py
index f2d0280676e05bbe18a7eec4f671b9419641bebe..270780a16446fc8785b36242f3b37213c70e234d 100644
--- a/modules/base/tests/test_table.py
+++ b/modules/base/tests/test_table.py
@@ -40,7 +40,7 @@ except ImportError:
   print "Could not find python imagine library: ignoring some table class unit tests"
 
 class TestTable(unittest.TestCase):
-  
+
   def setUp(self):
     ost.PushVerbosityLevel(3)
 
@@ -1289,7 +1289,5 @@ class TestTable(unittest.TestCase):
     self.assertAlmostEquals(tab.SpearmanCorrel('second','third'), -0.316227766)
     
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/bindings/tests/test_blast.py b/modules/bindings/tests/test_blast.py
index e8e151a4ec4a325658df4cee69c4b8d0b30feb47..8b4215faa45d71660a7799f3211885f519745a56 100644
--- a/modules/bindings/tests/test_blast.py
+++ b/modules/bindings/tests/test_blast.py
@@ -44,7 +44,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find blastall executable: ignoring unit tests"
     sys.exit(0)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/bindings/tests/test_clustalw.py b/modules/bindings/tests/test_clustalw.py
index 0fdb040db2b59f1a1a216a520059fb9d0f3faada..fa5a5e6b5eb44cbe11a0a11a68dc93d7d64cf123 100644
--- a/modules/bindings/tests/test_clustalw.py
+++ b/modules/bindings/tests/test_clustalw.py
@@ -68,7 +68,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find clustalw executable: ignoring unit tests"
     sys.exit(0)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/bindings/tests/test_msms.py b/modules/bindings/tests/test_msms.py
index 054a63cffa472d01fbef5d5cd20289cd0a409fb6..9041f94fab817441da03ae794fe63d793ad7d208 100755
--- a/modules/bindings/tests/test_msms.py
+++ b/modules/bindings/tests/test_msms.py
@@ -42,7 +42,5 @@ if __name__ == "__main__":
   version = msms.GetVersion(msms_exe=None, msms_env='MSMSSERVER')
   if version!=VERSION_REQUIRED:
     print "MSMS version (%s) does not match required version %s: ignoring unit tests"%(version, VERSION_REQUIRED)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/conop/tests/test_cleanup.py b/modules/conop/tests/test_cleanup.py
index ee6ab57cae413a550e1cc6abdbc7875a1d7d3210..1dc280f4fbaac9867c7f7a1063217bb4527cfbd0 100644
--- a/modules/conop/tests/test_cleanup.py
+++ b/modules/conop/tests/test_cleanup.py
@@ -158,5 +158,7 @@ class TestCleanUp(unittest.TestCase):
 if not hasattr(conop.GetBuilder(), 'compound_lib'):
   print 'Default builder without compound lib. Ignoring test_cleanup.py tests'
   sys.exit()
-suite = unittest.TestLoader().loadTestsFromTestCase(TestCleanUp)
-unittest.TextTestRunner().run(suite)
+
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/conop/tests/test_compound.py b/modules/conop/tests/test_compound.py
index 2c57bce756e0f26deab7e69467807993e96c51aa..a215a78f7a5dd966c2619346aaabf0f084b7bbd7 100644
--- a/modules/conop/tests/test_compound.py
+++ b/modules/conop/tests/test_compound.py
@@ -26,6 +26,6 @@ if __name__=='__main__':
   if not hasattr(builder, 'compound_lib'):
     print 'default builder does not use compound library. ignoring unit tests'
   else:
-    suite = unittest.TestLoader().loadTestsFromTestCase(TestCompound)
-    unittest.TextTestRunner().run(suite)
+    from ost import testutils
+    testutils.RunTests()
 
diff --git a/modules/conop/tests/test_nonstandard.py b/modules/conop/tests/test_nonstandard.py
index 57de3864e87575ffde1c7bdd705b5549f488fa31..170749c6eacd73bc64f4b6826e4df5d80f104512 100644
--- a/modules/conop/tests/test_nonstandard.py
+++ b/modules/conop/tests/test_nonstandard.py
@@ -121,7 +121,7 @@ if __name__ == "__main__":
   if not hasattr(builder, 'compound_lib'):
     print 'default builder does not use compound library. ignoring unit tests'
   else:
-    suite = unittest.TestLoader().loadTestsFromTestCase(TestNonStandard)
-    unittest.TextTestRunner().run(suite)
+    from ost import testutils
+    testutils.RunTests()
 
 
diff --git a/modules/geom/tests/test_geom.py b/modules/geom/tests/test_geom.py
index e25081bf1f0f305cf7928bd897566ade46c9c9e3..f563add91955b88fcc383b714df2f472a1a9b64e 100644
--- a/modules/geom/tests/test_geom.py
+++ b/modules/geom/tests/test_geom.py
@@ -80,5 +80,6 @@ class TestGeom(unittest.TestCase):
                       13,14,15,16])
     
 if __name__== '__main__':
-  unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
diff --git a/modules/gfx/tests/test_gfx.py b/modules/gfx/tests/test_gfx.py
index 0ddeeab7e2961fd9187f7e7bb9414ab8191c1a0a..ffca3b507ebbc6dfc8fe3d50c1701af75d0f0574 100644
--- a/modules/gfx/tests/test_gfx.py
+++ b/modules/gfx/tests/test_gfx.py
@@ -132,5 +132,6 @@ class TestGfx(unittest.TestCase):
                  
 
 if __name__== '__main__':
-  unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
diff --git a/modules/io/tests/test_io_mmcif.py b/modules/io/tests/test_io_mmcif.py
index 82c0be2e818eb7a9665da2002e32f730aee9c2c8..2a137b13b02d125043590ebfa7c268549bb150f7 100644
--- a/modules/io/tests/test_io_mmcif.py
+++ b/modules/io/tests/test_io_mmcif.py
@@ -155,6 +155,7 @@ class TestMMCifInfo(unittest.TestCase):
     self.assertEquals(i.GetObsoleteInfo().GetReplacedPDBID(), '2BAR')
 
 if __name__== '__main__':
-    unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
 
diff --git a/modules/io/tests/test_io_pdb.py b/modules/io/tests/test_io_pdb.py
index 6c43dd4214f6ea4c594f9833caa3edcde4137588..348fde1d929669405e612cb92d3a274ceb5636f1 100644
--- a/modules/io/tests/test_io_pdb.py
+++ b/modules/io/tests/test_io_pdb.py
@@ -26,7 +26,8 @@ class TestPDB(unittest.TestCase):
     self.assertTrue(mol.BondExists(res.FindAtom("CA"),res.FindAtom("CB")))
     
 if __name__== '__main__':
-    unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
 
- 
\ No newline at end of file
+ 
diff --git a/modules/mol/alg/tests/test_convenient_superpose.py b/modules/mol/alg/tests/test_convenient_superpose.py
index 7e03558c06647705589200688fb313df909e5c5b..eb4331ca3e8e6b65b0201197e5755cb2e5fcab15 100644
--- a/modules/mol/alg/tests/test_convenient_superpose.py
+++ b/modules/mol/alg/tests/test_convenient_superpose.py
@@ -193,4 +193,5 @@ class TestConvenientSuperpose(unittest.TestCase):
     self.assertEqualAtomOrder(view1, view2)
 
 if __name__ == "__main__":
-  unittest.main()
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_aligntoseqres.py b/modules/seq/alg/tests/test_aligntoseqres.py
index f31ff9ffa044ee25bdeff10ff11a30e33fbf1720..0f4b8ceaa9bdbdf61bec7a390127b6ebc6687f89 100644
--- a/modules/seq/alg/tests/test_aligntoseqres.py
+++ b/modules/seq/alg/tests/test_aligntoseqres.py
@@ -68,7 +68,5 @@ class TestAlignToSeqRes(unittest.TestCase):
     self.assertEqual(seq.alg.ValidateSEQRESAlignment(seqres_aln, chain), False)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_global_align.py b/modules/seq/alg/tests/test_global_align.py
index aed51741b8ef35f0afdbd02b250cc93ea1c05f23..b23503cd02c2fbd9684a4355cbb14e7e53120a02 100644
--- a/modules/seq/alg/tests/test_global_align.py
+++ b/modules/seq/alg/tests/test_global_align.py
@@ -44,7 +44,5 @@ class TestGlobalAlign(unittest.TestCase):
     self.assertEqual(alns[0].sequences[1].offset, 0)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_local_align.py b/modules/seq/alg/tests/test_local_align.py
index ff6872f9df22b261947e9abdbda12319e22a6d5a..47f78f68668e17e7413cbd18bbf09f9dd94b0b46 100644
--- a/modules/seq/alg/tests/test_local_align.py
+++ b/modules/seq/alg/tests/test_local_align.py
@@ -43,7 +43,5 @@ class TestLocalAlign(unittest.TestCase):
     self.assertEqual(alns[0].sequences[1].offset, 2)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_renumber.py b/modules/seq/alg/tests/test_renumber.py
index 76a9bf1d1d37284914ff7f23f2d32923c451d4f4..51e4727d3cfb7b3f87fea3517f9664fe7c896b16 100644
--- a/modules/seq/alg/tests/test_renumber.py
+++ b/modules/seq/alg/tests/test_renumber.py
@@ -118,7 +118,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find clustalw executable: ignoring unit tests"
     sys.exit(0)  
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_weight_matrix.py b/modules/seq/alg/tests/test_weight_matrix.py
index 7d85996fb3e74d0aa3ee87eace30a04881b0918a..91cf830379b7e7a3dccb5de3694267497f4d480f 100644
--- a/modules/seq/alg/tests/test_weight_matrix.py
+++ b/modules/seq/alg/tests/test_weight_matrix.py
@@ -39,7 +39,5 @@ class TestWeightMatrix(unittest.TestCase):
     self.assertEqual(mat.GetWeight('?', 'E'), 0)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/base/tests/test_seq.py b/modules/seq/base/tests/test_seq.py
index 7cc73a5cedb9cad4044948f840693b63bc72b16b..bfd80d7bf70461211962f6b36c2c603584b4fe4c 100644
--- a/modules/seq/base/tests/test_seq.py
+++ b/modules/seq/base/tests/test_seq.py
@@ -174,6 +174,8 @@ class TestSeq(unittest.TestCase):
     string_b=''.join([r.one_letter_code for r in b.residues])
     self.assertEqual(string_a, 'BDFH')
     self.assertEqual(string_b, 'BDFH')
-suite = unittest.TestLoader().loadTestsFromTestCase(TestSeq)
-unittest.TextTestRunner().run(suite)
+
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()