是否覆盖自定义输出的Python单元测试模块?[守则更新]

是否覆盖自定义输出的Python单元测试模块?[守则更新],python,unit-testing,python-2.7,overriding,python-unittest,Python,Unit Testing,Python 2.7,Overriding,Python Unittest,编辑: 解决了 将很快更新一个解决方案 目标: 我想重写Python的UnitTest模块,因此当我调用它时,我会在stdout流中得到以下JSON输出。例如: { "errors":0, "failures":1, "ran":3, "skipped":0, "successful":2, "test_data":[ { "index":0, "result":1 }, {

编辑: 解决了

将很快更新一个解决方案


目标:

我想重写Python的
UnitTest
模块,因此当我调用它时,我会在
stdout
流中得到以下JSON输出。例如:

{  
   "errors":0,
   "failures":1,
   "ran":3,
   "skipped":0,
   "successful":2,
   "test_data":[  
      {  
         "index":0,
         "result":1
      },
      {  
         "index":1,
         "result":1
      },
      {  
         "index":2,
         "result":-1
      }
   ]
}
问题:

我已经编写了一些代码来生成这些测试结果,但是在为JSON数组的
test\u data
属性编写代码时遇到了问题。我已经覆盖了
TestCase
TextTestResult
TextTestRunner
类,但我似乎不知道如何从
getTestsReport()
获取结果:

调用
getTestsReport()
后,
x
的值为什么不更新

编辑

好的,我认为
unittest.main(exit=False)
调用了错误的函数!我现在正试图重写main中的代码,但仍然面临一系列问题:

#!/usr/bin/python

import unittest
import sys, os
import json
import string

class MyTestRunner(unittest.TextTestRunner):

    def _makeResult(self):
        return MyTestResult(self.stream, self.descriptions, self.verbosity)

class MyTestResult(unittest._TextTestResult):

    """
        Holder for test result information.
        Test results are automatically managed by the TestCase and TestSuite
        classes, and do not need to be explicitly manipulated by writers of tests.

        Each instance holds the total number of tests run, and collections of
        failures and errors that occurred among those test runs. The collections
        contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
        formatted traceback of the error that occurred.
    """

    _previousTestClass = None
    _testRunEntered = False
    _moduleSetUpFailed = False

    def __init__(self, stream=None, descriptions=None, verbosity=None):
        self.failfast = False
        self.failures = []
        self.errors = []
        self.testsRun = 0
        self.skipped = []
        self.expectedFailures = []
        self.unexpectedSuccesses = []
        self.shouldStop = False
        self.buffer = False
        self._stdout_buffer = None
        self._stderr_buffer = None
        self._original_stdout = sys.stdout
        self._original_stderr = sys.stderr
        self._mirrorOutput = False

        # List containing all the run tests, their index and their result. This is the new line of code.
        self.tests_run = []

    def getTestsReport(self):
        """Returns the run tests as a list of the form [test_description, test_index, result]"""
        return self.tests_run

    ###
    ### Modified the functions so that we add the test case to the tests run list.
    ### -1 means Failure. 0 means error. 1 means success. 
    ###
    def addError(self, test, err):
        """
            Called when an error has occurred. 'err' is a tuple of values as
            returned by sys.exc_info().
        """
        self.errors.append((test, self._exc_info_to_string(err, test)))
        self._mirrorOutput = True
        self.tests_run.append([test.shortDescription(), self.testsRun, 0])
        TestResult.addError(self, test, err)

    def addFailure(self, test, err):
        """
            Called when an error has occurred. 'err' is a tuple of values as
            returned by sys.exc_info().
        """
        self.failures.append((test, self._exc_info_to_string(err, test)))
        self._mirrorOutput = True
        self.tests_run.append([test.shortDescription(), self.testsRun, -1])
        TestResult.addFailure(self, test, err)

    def addSuccess(self, test):
        "Called when a test has completed successfully"
        self.tests_run.append([test.shortDescription(), self.testsRun, 1])
        TestResult.addSuccess(self, test)


class MyTest(unittest.TestCase):

    currentResult = None # holds last result object passed to run method
    results = [] # Holds all results so we can report back to the CCC backend

    @classmethod
    def setResult(cls, amount, errors, failures, skipped):
        cls.amount, cls.errors, cls.failures, cls.skipped = \
            amount, errors, failures, skipped

    def tearDown(self):
        amount = self.currentResult.testsRun
        errors = self.currentResult.errors
        failures = self.currentResult.failures
        skipped = self.currentResult.skipped
        self.setResult(amount, errors, failures, skipped)

    @classmethod
    def tearDownClass(cls):
        print json.dumps(
            {
                'ran': cls.amount, 
                'errors': len(cls.errors),
                'failures': len(cls.failures),
                'succeeded': cls.amount - len(cls.errors) - len(cls.failures),
                'skipped': len(cls.skipped),
                'test_data' : dataHolder.x
            }, 
            sort_keys=True, indent=4, separators=(',', ': ')
        )

        return

    def run(self, result=None):
        self.currentResult = result # remember result for use in tearDown
        unittest.TestCase.run(self, result) # call superclass's run() method


    # Tests are defined below. 
    def test_something(self):
        self.assertEqual(1, 2)

if __name__ == '__main__':

    module = __import__('__main__')
    testRunner = MyTestRunner(verbosity=0)
    test = unittest.defaultTestLoader.loadTestsFromModule(module)
    print test
    test2 = unittest.defaultTestLoader.loadTestsFromNames(test, module)
    result = unittest.testRunner.run(test2)

有人能帮我吗?我被卡住了:(

如果你已经解决了它,请毫不犹豫地回答你自己的问题,并将该解决方案标记为已接受的答案。
#!/usr/bin/python

import unittest
import sys, os
import json
import string

class MyTestRunner(unittest.TextTestRunner):

    def _makeResult(self):
        return MyTestResult(self.stream, self.descriptions, self.verbosity)

class MyTestResult(unittest._TextTestResult):

    """
        Holder for test result information.
        Test results are automatically managed by the TestCase and TestSuite
        classes, and do not need to be explicitly manipulated by writers of tests.

        Each instance holds the total number of tests run, and collections of
        failures and errors that occurred among those test runs. The collections
        contain tuples of (testcase, exceptioninfo), where exceptioninfo is the
        formatted traceback of the error that occurred.
    """

    _previousTestClass = None
    _testRunEntered = False
    _moduleSetUpFailed = False

    def __init__(self, stream=None, descriptions=None, verbosity=None):
        self.failfast = False
        self.failures = []
        self.errors = []
        self.testsRun = 0
        self.skipped = []
        self.expectedFailures = []
        self.unexpectedSuccesses = []
        self.shouldStop = False
        self.buffer = False
        self._stdout_buffer = None
        self._stderr_buffer = None
        self._original_stdout = sys.stdout
        self._original_stderr = sys.stderr
        self._mirrorOutput = False

        # List containing all the run tests, their index and their result. This is the new line of code.
        self.tests_run = []

    def getTestsReport(self):
        """Returns the run tests as a list of the form [test_description, test_index, result]"""
        return self.tests_run

    ###
    ### Modified the functions so that we add the test case to the tests run list.
    ### -1 means Failure. 0 means error. 1 means success. 
    ###
    def addError(self, test, err):
        """
            Called when an error has occurred. 'err' is a tuple of values as
            returned by sys.exc_info().
        """
        self.errors.append((test, self._exc_info_to_string(err, test)))
        self._mirrorOutput = True
        self.tests_run.append([test.shortDescription(), self.testsRun, 0])
        TestResult.addError(self, test, err)

    def addFailure(self, test, err):
        """
            Called when an error has occurred. 'err' is a tuple of values as
            returned by sys.exc_info().
        """
        self.failures.append((test, self._exc_info_to_string(err, test)))
        self._mirrorOutput = True
        self.tests_run.append([test.shortDescription(), self.testsRun, -1])
        TestResult.addFailure(self, test, err)

    def addSuccess(self, test):
        "Called when a test has completed successfully"
        self.tests_run.append([test.shortDescription(), self.testsRun, 1])
        TestResult.addSuccess(self, test)


class MyTest(unittest.TestCase):

    currentResult = None # holds last result object passed to run method
    results = [] # Holds all results so we can report back to the CCC backend

    @classmethod
    def setResult(cls, amount, errors, failures, skipped):
        cls.amount, cls.errors, cls.failures, cls.skipped = \
            amount, errors, failures, skipped

    def tearDown(self):
        amount = self.currentResult.testsRun
        errors = self.currentResult.errors
        failures = self.currentResult.failures
        skipped = self.currentResult.skipped
        self.setResult(amount, errors, failures, skipped)

    @classmethod
    def tearDownClass(cls):
        print json.dumps(
            {
                'ran': cls.amount, 
                'errors': len(cls.errors),
                'failures': len(cls.failures),
                'succeeded': cls.amount - len(cls.errors) - len(cls.failures),
                'skipped': len(cls.skipped),
                'test_data' : dataHolder.x
            }, 
            sort_keys=True, indent=4, separators=(',', ': ')
        )

        return

    def run(self, result=None):
        self.currentResult = result # remember result for use in tearDown
        unittest.TestCase.run(self, result) # call superclass's run() method


    # Tests are defined below. 
    def test_something(self):
        self.assertEqual(1, 2)

if __name__ == '__main__':

    module = __import__('__main__')
    testRunner = MyTestRunner(verbosity=0)
    test = unittest.defaultTestLoader.loadTestsFromModule(module)
    print test
    test2 = unittest.defaultTestLoader.loadTestsFromNames(test, module)
    result = unittest.testRunner.run(test2)