あいつの日誌β

働きながら旅しています。

py.test の xdist の挙動を確認してみた

あらすじ

  • test.py(xdist)で並列テストを実行しているプロジェクトが存在する。
  • 現在、関数毎にテスト用の redis-server を起動して、都度廃棄している。
  • redis-server を起動する処理をモジュール単位に変更し、テスト関数が始まる度に flushall() にする処理に変更したい。

というわけで検証してみた。

準備したファイル

% cat tests/conftest.py
# -*- coding: utf-8 -*-
import os
import pytest
import inspect
import logging
logging.basicConfig(filename='pytest.log',level=logging.DEBUG)

def _log():
    def_name = inspect.currentframe().f_back.f_code.co_name
    logging.debug('%s:%s' % (os.getpid(), def_name))

@pytest.fixture(scope='module', autouse=True)
def module():
    _log()

@pytest.fixture(scope='function', autouse=True)
def function():
    _log()
% cat tests/test_pytest.py
# -*- coding: utf-8 -*-
import os
import pytest
import inspect
import logging
logging.basicConfig(filename='pytest.log',level=logging.DEBUG)

def _log():
    def_name = inspect.currentframe().f_back.f_code.co_name
    logging.debug('%s:%s' % (os.getpid(), def_name))

class TestMy(object):

    def test_001(self):
        _log()

    def test_002(self):
        _log()

    def test_003(self):
        _log()

    def test_004(self):
        _log()

    def test_005(self):
        _log()

    def test_006(self):
        _log()

    def test_007(self):
        _log()

    def test_008(self):
        _log()

    def test_009(self):
        _log()

    def test_010(self):
        _log()

実験開始

py.test を4つのプロセスで実行する

% py.test tests/test_pytest.py -n 4
==================================== test session starts =====================================
platform darwin -- Python 2.7.3 -- py-1.4.27 -- pytest-2.7.1
rootdir: /Users/okamura/python/pytest-scope/tests, inifile: 
plugins: fixture-tools, xdist
gw0 [10] / gw1 [10] / gw2 [10] / gw3 [10]
scheduling tests via LoadScheduling
..........
================================= 10 passed in 0.61 seconds ==================================

ログを確認

% cat pytest.log
DEBUG:root:90675:module
DEBUG:root:90675:function
DEBUG:root:90674:module
DEBUG:root:90674:function
DEBUG:root:90677:module
DEBUG:root:90675:test_001
DEBUG:root:90674:test_007
DEBUG:root:90677:function
DEBUG:root:90676:module
DEBUG:root:90677:test_003
DEBUG:root:90676:function
DEBUG:root:90674:function
DEBUG:root:90675:function
DEBUG:root:90674:test_008
DEBUG:root:90675:test_002
DEBUG:root:90676:test_005
DEBUG:root:90675:function
DEBUG:root:90674:function
DEBUG:root:90675:test_010
DEBUG:root:90677:function
DEBUG:root:90674:test_009
DEBUG:root:90677:test_004
DEBUG:root:90676:function
DEBUG:root:90676:test_006

見辛いので grep する

% cat pytest.log | grep 90675
DEBUG:root:90675:module
DEBUG:root:90675:function
DEBUG:root:90675:test_001
DEBUG:root:90675:function
DEBUG:root:90675:test_002
DEBUG:root:90675:function
DEBUG:root:90675:test_010

まとめ

  • テストケースは(-nで指定された)4つのプロセスに分割され並列に実行される
  • module単位の fixture は各プロセスが1度だけ実行するので、合計で4回実行される
  • test_001からtest_010 のテストケースは4つのプロセスのいずれかで実行される
  • 同じプロセス内では順次に処理が実行される

よってモジュール単位で redis-server を起動させた場合(port や dbfile などは独立しているとする)、それぞれのテストケースで影響が出る事はないでしょう。

あとがき

ちなみに -n で指定できる数値は CPU の コア数 * スレッド数 のようです。