2014-08-27 17 views
8

Urządzenie tmpdir w py.test używa zakresu function i dlatego nie jest dostępne w urządzeniu o szerszym zakresie, takim jak session. Byłoby to jednak przydatne w niektórych przypadkach, takich jak konfiguracja tymczasowego serwera PostgreSQL (którego oczywiście nie powinno się odtwarzać dla każdego testu).py.test: folder tymczasowy dla zakresu sesji

Czy istnieje jakiś czysty sposób na uzyskanie folderu tymczasowego o szerszym zasięgu, który nie wymaga pisania własnego urządzenia i dostępu do wewnętrznych interfejsów API py.test?

Odpowiedz

13

Niestety obecnie nie ma sposobu na ładnie to zrobić. W przyszłości py.test wprowadzi nowy "dowolny" zakres lub coś podobnego do tego, ale taka jest przyszłość.

Teraz musisz zrobić to ręcznie samodzielnie. Jednakże, jak zauważyłeś, tracisz kilka fajnych funkcji: dowiązania symboliczne w/tmp do ostatniego testu, automatyczne czyszczenie po kilku testach, sensownie nazwane katalogi itp. Jeśli katalog nie jest zbyt drogi, zazwyczaj łączę sesję i funkcję o ustalonym zakresie w następujący sposób:

@pytest.fixture(scope='session') 
def sessiondir(request): 
    dir = py.path.local(tempfile.mkdtemp()) 
    request.addfinalizer(lambda: dir.remove(rec=1)) 
    # Any extra setup here 
    return dir 

@pytest.fixture 
def dir(sessiondir, tmpdir): 
    sessiondir.copy(tmpdir) 
    return tmpdir 

to tworzy katalog tymczasowy, który zostanie oczyszczony się po okresie testowym, jednak dla każdego testu, który rzeczywiście potrzebuje go (poprzez zwrócenie dir) dostaje kopię który jest zapisany z semantyki tmpdir.

Jeśli testy rzeczywiście muszą współdzielić stan za pośrednictwem tego katalogu, to finalizator dir musiałby skopiować dane z powrotem do sesji. Nie jest to jednak bardzo dobry pomysł, ponieważ sprawia, że ​​testy zależą od kolejności wykonania, a także powodują problemy podczas używania programu pytest-xdist.

+0

Czy my napotkasz żadnych problemów, jeśli po prostu kopiowane z wbudowanej TMPDIR na nową nazwę wtyczki i zakresu to jak chcemy? – ajwood

+0

Prawdopodobnie IIRC nazwa tmpdir zależy od zakresu funkcji i może powodować problemy. Ale nie sprawdziłem, spróbuj, jeśli chcesz! – flub

+0

Od wersji 2.8 już tak nie jest. Zobacz https://stackoverflow.com/a/38050261/384617. –

-1

Oto inne podejście. Wygląda na to, że pytest nie usuwa tymczasowych katalogów po uruchomieniach testowych. Poniżej przedstawiono standardowe urządzenie o zakresie funkcjonalnym.

# conftest.py 
TMPDIRS = list() 

@pytest.fixture 
def tmpdir_session(tmpdir): 
    """A tmpdir fixture for the session scope. Persists throughout the session.""" 
    if not TMPDIRS: 
     TMPDIRS.append(tmpdir) 
    return TMPDIRS[0] 

I mieć trwałe tymczasowe katalogi całej modułów zamiast całej sesji pytest:

# conftest.py 
TMPDIRS = dict() 

@pytest.fixture 
def tmpdir_module(request, tmpdir): 
    """A tmpdir fixture for the module scope. Persists throughout the module.""" 
    return TMPDIRS.setdefault(request.module.__name__, tmpdir) 

Edit: Oto kolejny rozwiązanie, które nie wymaga zmiennych globalnych. pytest 1.8.0 wprowadzono tmpdir_factory urządzenie, które można używać:

@pytest.fixture(scope='module') 
def tmpdir_module(request, tmpdir_factory): 
    """A tmpdir fixture for the module scope. Persists throughout the module.""" 
    return tmpdir_factory.mktemp(request.module.__name__) 


@pytest.fixture(scope='session') 
def tmpdir_session(request, tmpdir_factory): 
    """A tmpdir fixture for the session scope. Persists throughout the pytest session.""" 
    return tmpdir_factory.mktemp(request.session.name) 
+0

Dlaczego zamiast używać zmiennych globalnych nie używasz 'scope = 'session'' i' scope =' module''? – ThiefMaster

+0

Informacje o nie usuwaniu części są pół-prawdziwe: zachowuje ostatnie 3 katalogi tymczasowe, które wymieniono gdzieś w dokumentach, tj. Jest to funkcja. – ThiefMaster

+0

Nie można użyć scope = 'session' lub 'module', gdy używasz wbudowanego urządzenia tmpdir. Pojawi się wyjątek informujący, że próbujesz użyć urządzenia o zakresie funkcjonalnym w zasięgu urządzenia sesji/modułu. Stąd to obejście. – Robpol86

9

Ponieważ pytest uwolnienia 2,8 i powyżej sesji o zakresie tmpdir_factory Urządzenie jest dostępne. Zobacz przykład poniżej z documentation.

# contents of conftest.py 
import pytest 

@pytest.fixture(scope='session') 
def image_file(tmpdir_factory): 
    img = compute_expensive_image() 
    fn = tmpdir_factory.mktemp('data').join('img.png') 
    img.save(str(fn)) 
    return fn 

# contents of test_image.py 
def test_histogram(image_file): 
    img = load_image(image_file) 
    # compute and test histogram 
0

dodaję finalizatora gdy chcę usunąć wszystkie foldery tymczasowe utworzonych w sesji.

_tmp_factory = None 
@pytest.fixture(scope="session") 
def tmp_factory(request, tmpdir_factory): 
    global _tmp_factory 
    if _tmp_factory is None: 
     _tmp_factory = tmpdir_factory 
     request.addfinalizer(cleanup) 
    return _tmp_factory 

def cleanup(): 
    root = _tmp_factory.getbasetemp().strpath 
    print "Cleaning all temporary folders from %s" % root 
    shutil.rmtree(root) 

def test_deleting_temp(tmp_factory): 
    root_a = tmp_factory.mktemp('A') 
    root_a.join('foo.txt').write('hello world A') 

    root_b = tmp_factory.mktemp('B') 
    root_b.join('bar.txt').write('hello world B') 

    for root, _, files in os.walk(tmp_factory.getbasetemp().strpath): 
     for name in files: 
      print(os.path.join(root, name)) 

Wyjście powinno być tak:

/tmp/pytest-of-agp/pytest-0/.lock 
/tmp/pytest-of-agp/pytest-0/A0/foo.txt 
/tmp/pytest-of-agp/pytest-0/B0/bar.txt 
Cleaning all temporary folders from /tmp/pytest-of-agp/pytest-0