如何让PyCharm显示使用多个进程的程序的代码覆盖?

时间:2014-07-29 23:37:01

标签: python unit-testing code-coverage pycharm

我们说我创建了这个简单的模块并将其命名为MyModule.py:

import threading
import multiprocessing
import time

def workerThreaded():
    print 'thread working...'
    time.sleep(2)
    print 'thread complete'

def workerProcessed():
    print 'process working...'
    time.sleep(2)
    print 'process complete'

def main():
    workerThread = threading.Thread(target=workerThreaded)
    workerThread.start()
    workerProcess = multiprocessing.Process(target=workerProcessed)
    workerProcess.start()
    workerThread.join()
    workerProcess.join()

if __name__ == '__main__':
    main()

然后我把它扔到一起进行单元测试:

import unittest
import MyModule

class MyModuleTester(unittest.TestCase):
    def testMyModule(self):
        MyModule.main()

unittest.main()

(我知道这不是一个好的单元测试,因为它实际上没有测试它,它只是运行它,但这与我的问题无关)

如果我在PyCharm中使用代码覆盖率运行此单元测试,那么它只显示workerThreaded()main()函数中的代码,尽管它明确涵盖了workerProcessed()功能也很好。

如何让PyCharm在其代码覆盖率中包含在新流程中启动的代码?另外,我怎样才能让它包含if __name__ == '__main__':块?

我正在运行PyCharm 2.7.3以及Python 2.7.3。

2 个答案:

答案 0 :(得分:1)

Coverage.py可以衡量在子流程中运行的代码,详细信息位于http://nedbatchelder.com/code/coverage/subprocess.html

答案 1 :(得分:0)

我设法使其与子进程一起使用,不确定是否可以与线程或python 2一起使用。

在项目根目录中创建.covergerc文件

[run]
concurrency=multiprocessing

在项目根目录中创建sitecustomize.py文件

import atexit
from glob import glob

import os
from functools import partial
from shutil import copyfile
from tempfile import mktemp


def combine_coverage(coverage_pattern, xml_pattern, old_coverage, old_xml):
    from coverage.cmdline import main
    # Find newly created coverage files
    coverage_files = [file for file in glob(coverage_pattern) if file not in old_coverage]
    xml_files = [file for file in glob(xml_pattern) if file not in old_xml]

    if not coverage_files:
        raise Exception("No coverage files generated!")

    if not xml_files:
        raise Exception("No coverage xml file generated!")

    # Combine all coverage files
    main(["combine", *coverage_files])

    # Convert them to xml
    main(["xml"])

    # Copy combined xml file over PyCharm generated one
    copyfile('coverage.xml', xml_files[0])
    os.remove('coverage.xml')


def enable_coverage():
    import coverage
    # Enable subprocess monitoring by providing rc file and enable coverage collecting
    os.environ['COVERAGE_PROCESS_START'] = os.path.join(os.path.dirname(__file__), '.coveragerc')
    coverage.process_startup()

    # Get current coverage files so we can process only newly created ones
    temp_root = os.path.dirname(mktemp())
    coverage_pattern = '%s/pycharm-coverage*.coverage*' % temp_root
    xml_pattern = '%s/pycharm-coverage*.xml' % temp_root
    old_coverage = glob(coverage_pattern)
    old_xml = glob(xml_pattern)

    # Register atexit handler to collect coverage files when python is shutting down
    atexit.register(partial(combine_coverage, coverage_pattern, xml_pattern, old_coverage, old_xml))


if os.getenv('PYCHARM_RUN_COVERAGE'):
    enable_coverage()

这基本上可以检测代码是否在PyCharm Coverage中运行,并收集新生成的coverage文件。有多个文件,一个用于主进程,一个用于每个子进程。因此,我们需要将它们与“ coverage Combine”结合起来,然后通过“ coverage xml”将它们转换为xml,然后将结果文件复制到PyCharm生成的xml文件中。

请注意,如果您在测试coverage中杀死了子进程,py将不会写入数据文件。

不需要任何其他操作,只需点击PyCharm中的“使用Coverage运行单元测试”按钮即可。

就是这样。