14.4 将测试输出用日志记录到文件中
最后更新于:2022-04-01 15:40:23
## 问题
You want the results of running unit tests written to a file instead of printed to standardoutput.
## 解决方案
A very common technique for running unit tests is to include a small code fragmentlike this at the bottom of your testing file:
import unittest
class MyTest(unittest.TestCase):...if __name__ == ‘__main__':unittest.main()
This makes the test file executable, and prints the results of running tests to standardoutput. If you would like to redirect this output, you need to unwind the main() call abit and write your own main() function like this:
import sysdef main(out=sys.stderr, verbosity=2):
> loader = unittest.TestLoader()suite = loader.loadTestsFromModule(sys.modules[__name__])unittest.TextTestRunner(out,verbosity=verbosity).run(suite)
if __name__ == ‘__main__':with open(‘testing.out', ‘w') as f:main(f)
## 讨论
The interesting thing about this recipe is not so much the task of getting test resultsredirected to a file, but the fact that doing so exposes some notable inner workings ofthe unittest module.At a basic level, the unittest module works by first assembling a test suite. This testsuite consists of the different testing methods you defined. Once the suite has beenassembled, the tests it contains are executed.
These two parts of unit testing are separate from each other. The unittest.TestLoader instance created in the solution is used to assemble a test suite. The loadTestsFromModule() is one of several methods it defines to gather tests. In this case, it scans amodule for TestCase classes and extracts test methods from them. If you want some‐thing more fine-grained, the loadTestsFromTestCase() method (not shown) can beused to pull test methods from an individual class that inherits from TestCase.The TextTestRunner class is an example of a test runner class. The main purpose ofthis class is to execute the tests contained in a test suite. This class is the same test runnerthat sits behind the unittest.main() function. However, here we’re giving it a bit oflow-level configuration, including an output file and an elevated verbosity level.Although this recipe only consists of a few lines of code, it gives a hint as to how youmight further customize the unittest framework. To customize how test suites areassembled, you would perform various operations using the TestLoader class. To cus‐tomize how tests execute, you could make custom test runner classes that emulate thefunctionality of TextTestRunner. Both topics are beyond the scope of what can be cov‐ered here. However, documentation for the unittest module has extensive coverageof the underlying protocols.