2017年7月11日 星期二

[ Python 常見問題 ] unittest - Show progress while running python unittest?

Source From Here 
Question 
I have a very large TestSuite that I run with TextTestRunner from the python unittest framework. Unfortunately I have no idea how many tests are already done while the test are running. 

Basically I'd like to convert this output: 
  1. test_choice (__main__.TestSequenceFunctions) ... ok  
  2. test_sample (__main__.TestSequenceFunctions) ... ok  
  3. test_shuffle (__main__.TestSequenceFunctions) ... ok  
  4.   
  5. ----------------------------------------------------------------------  
  6. Ran 3 tests in 0.110s  
  7.   
  8. OK  
to 
  1. [1/3] test_choice (__main__.TestSequenceFunctions) ... ok  
  2. [2/3] test_sample (__main__.TestSequenceFunctions) ... ok  
  3. [3/3] test_shuffle (__main__.TestSequenceFunctions) ... ok  
  4.   
  5. ----------------------------------------------------------------------  
  6. Ran 3 tests in 0.110s  
  7.   
  8. OK  
Do I have to subclass TextTestRunner to achieve this and if yes, how? 

How-To 
Here's one way that you could subclass TextTestRunner and TextTestResult to achieve the desired result: 
- demo_unittest.py 
  1. #!/usr/bin/env python  
  2. import unittest  
  3. import unittest.runner  
  4. import itertools  
  5. import collections  
  6.   
  7. class CustomTextTestResult(unittest.runner.TextTestResult):  
  8.     """Extension of TextTestResult to support numbering test cases"""  
  9.   
  10.     def __init__(self, stream, descriptions, verbosity):  
  11.         """Initializes the test number generator, then calls super impl"""  
  12.   
  13.         self.test_numbers = itertools.count(1)  
  14.   
  15.         return super(CustomTextTestResult, self).__init__(stream, descriptions, verbosity)  
  16.   
  17.     def startTest(self, test):  
  18.         """Writes the test number to the stream if showAll is set, then calls super impl"""  
  19.   
  20.         if self.showAll:  
  21.             progress = '[{0}/{1}] '.format(next(self.test_numbers), self.test_case_count)  
  22.             self.stream.write(progress)  
  23.   
  24.             # Also store the progress in the test itself, so that if it errors,  
  25.             # it can be written to the exception information by our overridden  
  26.             # _exec_info_to_string method:  
  27.             test.progress_index = progress  
  28.   
  29.         return super(CustomTextTestResult, self).startTest(test)  
  30.   
  31.     def _exc_info_to_string(self, err, test):  
  32.         """Gets an exception info string from super, and prepends 'Test Number' line"""  
  33.   
  34.         info = super(CustomTextTestResult, self)._exc_info_to_string(err, test)  
  35.   
  36.         if self.showAll:  
  37.             info = 'Test number: {index}\n{info}'.format(  
  38.                 index=test.progress_index,  
  39.                 info=info  
  40.             )  
  41.   
  42.         return info  
  43.   
  44.   
  45. class CustomTextTestRunner(unittest.runner.TextTestRunner):  
  46.     """Extension of TextTestRunner to support numbering test cases"""  
  47.   
  48.     resultclass = CustomTextTestResult  
  49.   
  50.     def run(self, test):  
  51.         """Stores the total count of test cases, then calls super impl"""  
  52.         self.test_case_count = test.countTestCases()  
  53.         return super(CustomTextTestRunner, self).run(test)  
  54.   
  55.     def _makeResult(self):  
  56.         """Creates and returns a result instance that knows the count of test cases"""  
  57.   
  58.         result = super(CustomTextTestRunner, self)._makeResult()  
  59.         result.test_case_count = self.test_case_count  
  60.         return result  
  61.   
  62. class TestSequenceFunctions(unittest.TestCase):  
  63.     """Dummy test case to illustrate usage"""  
  64.   
  65.     fail_1 = 0  
  66.     fail_2 = 0  
  67.   
  68.     def test_choice(self):  
  69.         pass  
  70.   
  71.     def test_sample(self):  
  72.         self.fail_1 += 1  
  73.         if self.fail_1 == 2:  
  74.             raise Exception()  
  75.   
  76.     def test_shuffle(self):  
  77.         self.fail_2 += 1  
  78.         if self.fail_2 == 3:  
  79.             raise Exception()  
  80.   
  81.   
  82. def get_tests():  
  83.     test_funcs = ['test_choice', 'test_sample', 'test_shuffle']  
  84.     return [TestSequenceFunctions(func) for func in test_funcs]  
  85.   
  86.   
  87. if __name__ == '__main__':  
  88.     test_suite = unittest.TestSuite()  
  89.   
  90.     repetitions = 3  
  91.     tests = get_tests()  
  92.     for __ in xrange(0, repetitions):  
  93.         test_suite.addTests(tests)  
  94.   
  95.     CustomTextTestRunner(verbosity=2).run(test_suite)  
Execution result: 
# ./demo_unittest.py 
[1/9] test_choice (__main__.TestSequenceFunctions) ... ok 
[2/9] test_sample (__main__.TestSequenceFunctions) ... ok 
[3/9] test_shuffle (__main__.TestSequenceFunctions) ... ok 
[4/9] test_choice (__main__.TestSequenceFunctions) ... ok 
[5/9] test_sample (__main__.TestSequenceFunctions) ... ERROR 
[6/9] test_shuffle (__main__.TestSequenceFunctions) ... ok 
[7/9] test_choice (__main__.TestSequenceFunctions) ... ok 
[8/9] test_sample (__main__.TestSequenceFunctions) ... ok 
[9/9] test_shuffle (__main__.TestSequenceFunctions) ... ERROR 

====================================================================== 
ERROR: test_sample (__main__.TestSequenceFunctions) 
---------------------------------------------------------------------- 
Test number: [5/9] 
Traceback (most recent call last): 
File "./demo_unittest.py", line 75, in test_sample 
raise Exception() 
Exception 

====================================================================== 
ERROR: test_shuffle (__main__.TestSequenceFunctions) 
---------------------------------------------------------------------- 
Test number: [9/9] 
Traceback (most recent call last): 
File "./demo_unittest.py", line 80, in test_shuffle 
raise Exception() 
Exception 

---------------------------------------------------------------------- 
Ran 9 tests in 0.001s 

FAILED (errors=2)


沒有留言:

張貼留言

[Linux 常見問題] What's the best way to send a signal to all members of a process group?

Source From  Here   Question   I want to  kill a whole process tree.  What is the best way to do this using any common scripting languages? ...