Pytest выполняется дважды и пропускается один раз

#python #pytest

Вопрос:

Когда я вызываю pytest свой скрипт slurm, журнал тестового сеанса показывает, что все test_<test_name>.py файлы вызываются дважды, при этом в первый раз они пропускаются, а во второй раз они выполняются:

 [1m============================= test session starts ==============================[0m
platform linux -- Python 3.8.5, pytest-5.2.0, py-1.9.0, pluggy-0.13.1 -- /n/sw/eb/apps/centos7/Anaconda3/2020.11/bin/python
cachedir: .pytest_cache
rootdir: <removed for privacy reasons>, inifile: pytest.ini, testpaths: tests
plugins: flakes-2.0.0, pythonpath-0.7.3, cov-2.6.1, pep8-1.0.6, anyio-2.2.0
[1mcollecting ... [0mcollected 25 items

tests/conftest.py [32mPASSED[0m[36m                                                 [  4%][0m
tests/conftest.py [32mPASSED[0m[36m                                                 [  4%][0m
tests/test_base_dataset.py [33mSKIPPED[0m[36m                                       [  8%][0m
tests/test_base_dataset.py [32mPASSED[0m[36m                                        [  8%][0m
tests/test_base_dataset.py::test_base_dataset [32mPASSED[0m[36m                     [ 12%][0m
tests/test_base_model.py [33mSKIPPED[0m[36m                                         [ 16%][0m
tests/test_base_model.py [32mPASSED[0m[36m                                          [ 16%][0m
tests/test_base_model.py::test_base_dataset [32mPASSED[0m[36m                       [ 20%][0m
tests/test_base_options.py [33mSKIPPED[0m[36m                                       [ 24%][0m
tests/test_base_options.py [32mPASSED[0m[36m                                        [ 24%][0m
 

Это приводит к окончательному выводу:

 [32m[1m======================== 19 passed, 6 skipped in 6.36s =========================[0m
 

Что может привести к такому поведению?

Я импортирую только pytest один раз в моем conftest.py

conftest.py — по просьбе SergioLema в комментариях

 import pytest
import numpy as np
import torch
import argparse
from options.train_options import TrainOptions
from data.base_dataset import BaseDataset
from models.base_model import BaseModel
from models.cycle_gan_model import CycleGANModel
from data.image_folder import ImageFolder


# test base dataset
class TestDataset(BaseDataset):
    """Test implementation of the BaseDataset class
    """

    __test__ = False

    def __init__(self, opt):
        BaseDataset.__init__(self, opt)
        self.dummy_data = np.asarray([np.random.random((2, 2)) for _ in range(0, 3)])

    def __len__(self):
        return self.dummy_data.shape[0]

    def __getitem__(self, index):
        return self.dummy_data[index]


class TestOption(BaseOptions):
    __test__ = False

    def __init__(self, parser):
        BaseOptions.initialize(self, parser)

@pytest.fixture(scope="function")
def option_constructor():
    yield TestOption(argparse.ArgumentParser(description="Test parser"))


@pytest.fixture(scope="function")
def base_dataset(ran_root):
    yield TestDataset(ran_root)


# test image folder
@pytest.fixture(scope="function")
def image_folder_instance(dummy_data):
    yield ImageFolder(dummy_data)


# test base options
@pytest.fixture(scope="module")
def dummy_data():
    yield "/n/pfister_lab2/Lab/leander/cust_cgan/ccgan/tests/dummy_data"


# test train options
@pytest.fixture(scope="function")
def train_options(dummy_data):
    yield TrainOptions().parse(['--dataroot', dummy_data, '--name', 'test_cyclegan',
                                '--model', 'cycle_gan', '--lambda_identity', '0.0'])


@pytest.fixture(scope="function")
def train_options_match_encoding(dummy_data):
    yield TrainOptions().parse(['--dataroot', dummy_data, '--name', 'test_cyclegan',
                                '--model', 'cycle_gan', '--match_encoding', 'True',
                                '--match_encoding_weight', '0.5'])


# test base model
class TestBaseModel(BaseModel):

    __test__ = False

    def __init__(self, opt):
        BaseModel.__init__(self, opt)

    def set_input(self, input):
        pass

    def forward(self):
        pass

    def optimize_parameters(self):
        pass


@pytest.fixture(scope="function")
def base_model(train_options):
    yield TestBaseModel(train_options)


# test cycle_gan model
@pytest.fixture(scope='function')
def cycleGAN_instance(train_options):
    yield CycleGANModel(train_options)


@pytest.fixture(scope='function')
def cycleGAN_match_encoding_instance(train_options_match_encoding):
    yield CycleGANModel(train_options_match_encoding)


@pytest.fixture(scope='module')
def input():
    A_data = torch.stack([torch.randn(3, 32, 32) for _ in range(0, 2)])
    B_data = torch.stack([torch.randn(3, 32, 32) for _ in range(0, 2)])
    A_path = ["path_of_img_A_{0}".format(i) for i in range(0, 2)]
    B_path = ["path_of_img_B_{0}".format(i) for i in range(0, 2)]
    yield {'A': A_data, 'B': B_data, 'A_paths': A_path, 'B_paths': B_path}
 

test_base_options.py — по просьбе Shod в комментариях

 from options.test_options import TestOptions


def test_base_options(dummy_data):
    opt = TestOptions().parse(["--dataroot", dummy_data])
    assert (opt.dataroot == dummy_data)

 

Комментарии:

1. Не могли бы вы показать нам conftest.py и как вы запускаете свои тесты из командной строки?

2. @SergioLema Я добавил conftest.py досье. Я вызываю pytest из скрипта SLURM и не имею прямого доступа к командной строке. Я либо вызываю pytest , либо pytest -k test_<test_abrivation> . В обоих случаях я вижу поведение, описанное выше

3. можете ли вы показать содержимое test_<test_name>.py ?

4. @Shod У меня есть несколько тестовых файлов. Однако, чтобы ответить на ваш вопрос, я удалил все файлы, кроме одного, и сократил файл до одного фиктивного теста (см. test_base_options.py Выше). Когда я запускаю pytest снова, проблема сохраняется.

5. @L.Lauenburg можете ли вы удалить Test префикс из тестовых классов conftest.py и проверить один раз? Я знаю, что вы уже упоминали __test__ = False , но идк, также проверьте эту проблему . Кроме того, попробуйте передать -vvv , чтобы получить больше подробностей для отладки..