Jak drukować do konsoli w pytest?


175

Próbuję używać TDD (programowanie oparte na testach) z pytest. pytestnie printdo konsoli, kiedy używam print.

Używam go pytest my_tests.pydo uruchomienia.

documentationZdaje się mówić, że to powinno działać domyślnie: http://pytest.org/latest/capture.html

Ale:

import myapplication as tum

class TestBlogger:

    @classmethod
    def setup_class(self):
        self.user = "alice"
        self.b = tum.Blogger(self.user)
        print "This should be printed, but it won't be!"

    def test_inherit(self):
        assert issubclass(tum.Blogger, tum.Site)
        links = self.b.get_links(posts)
        print len(links)   # This won't print either.

Nic nie jest drukowane na mojej standardowej konsoli wyjściowej (tylko normalny postęp i ile testów przeszło / zakończyło się niepowodzeniem).

A skrypt, który testuję, zawiera print:

class Blogger(Site):
    get_links(self, posts):
        print len(posts)   # It won't get printed in the test.

W unittestmodule wszystko jest domyślnie drukowane, czyli dokładnie to, czego potrzebuję. Chciałbym jednak użyć pytestz innych powodów.

Czy ktoś wie, jak wyświetlić instrukcje drukowania?


1
Może stdout jest nadpisywane. Co się stanie, jeśli użyjesz sys.stdout.write("Test")? A co powiesz sys.__stdout__.write("Test")? Ten ostatni powinien zawsze zapisywać do standardowego wyjścia zdefiniowanego przez system, którym powinna być konsola. Jeśli te dwie komendy robią różne rzeczy, to stdout jest zmieniane; jeśli robią to samo, problem jest inny.
TheSoundDefense

Odpowiedzi:


205

Domyślnie py.testprzechwytuje wynik standardowego wyjścia, aby mógł kontrolować sposób jego drukowania. Gdyby tego nie zrobił, wyplułby dużo tekstu bez kontekstu, jaki test wydrukował ten tekst.

Jeśli jednak test się nie powiedzie, w wynikowym raporcie będzie zawierał sekcję, która pokazuje, co zostało wydrukowane do standardowego wykonania w tym konkretnym teście.

Na przykład,

def test_good():
    for i in range(1000):
        print(i)

def test_bad():
    print('this should fail!')
    assert False

Daje następujący wynik:

>>> py.test tmp.py
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py .F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
------------------------------- Captured stdout --------------------------------
this should fail!
====================== 1 failed, 1 passed in 0.04 seconds ======================

Zwróć uwagę na Captured stdoutsekcję.

Jeśli chcesz zobaczyć printinstrukcje w trakcie ich wykonywania, możesz przekazać -sflagę do py.test. Należy jednak pamiętać, że czasami może to być trudne do przeanalizowania.

>>> py.test tmp.py -s
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py 0
1
2
3
... and so on ...
997
998
999
.this should fail!
F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
====================== 1 failed, 1 passed in 0.02 seconds ======================

2
Niezwykle praktyczny. Dobra robota!
cmc

1
hmm ... nadal nie rejestruje moich wydruków
Tim Boland

68

Użycie -sopcji wypisze wynik wszystkich funkcji, których może być za dużo.

Jeśli potrzebujesz konkretnych wyników, wspomniana strona dokumentacji zawiera kilka sugestii:

  1. Wstaw assert False, "dumb assert to make PyTest print my stuff"na końcu swojej funkcji, a zobaczysz wynik z powodu niepowodzenia testu.

  2. Masz specjalny obiekt przekazany ci przez PyTest i możesz zapisać wynik do pliku, aby sprawdzić go później, na przykład

    def test_good1(capsys):
        for i in range(5):
            print i
        out, err = capsys.readouterr()
        open("err.txt", "w").write(err)
        open("out.txt", "w").write(out)

    Możesz otworzyć pliki outi errna osobnej karcie i pozwolić edytorowi automatycznie je odświeżyć lub wykonać proste py.test; cat out.txtpolecenie powłoki, aby uruchomić test.

To raczej hakerski sposób na robienie rzeczy, ale może to jest rzecz, której potrzebujesz: w końcu TDD oznacza, że ​​majstrujesz i zostawiasz ją czystą i cichą, gdy będzie gotowa :-).


Wypróbowałem wersję 1. z pytest 3.8.1 niestety wypisuje tylko blok funkcyjny test, ale nie wypisuje instrukcji print :( więcej sztuczek do tego?
UV

@UV - Zamiast używać print()funkcji, powinieneś umieścić zmienną lub wiadomość, którą zamierzasz wydrukować po przecinku w instrukcji assert. Np. assert False, what_are_youwhat_are_youWypisze ” wartość w raporcie pytest.
Mart Van de Ven

43

Krótka odpowiedź

Skorzystaj z -sopcji:

pytest -s

Szczegółowa odpowiedź

Z dokumentów :

Podczas wykonywania testu przechwytywane są wszystkie dane wyjściowe wysyłane na stdout i stderr . Jeśli test lub metoda konfiguracji nie powiedzie się, jej odpowiednio przechwycone dane wyjściowe będą zwykle wyświetlane wraz ze śledzeniem awarii.

pytestma możliwość --capture=method, w której methodjest za-testu przechwytywania sposób i może być jednym z następujących: fd, sysi no. pytestma również opcję, -sktóra jest skrótem --capture=no, i jest to opcja, która pozwoli ci zobaczyć swoje instrukcje print w konsoli.

pytest --capture=no     # show print statements in console
pytest -s               # equivalent to previous command

Ustawianie metod przechwytywania lub wyłączanie przechwytywania

Istnieją dwa sposoby pytestprzechwytywania:

  1. przechwytywanie poziomu deskryptora plików (FD) (domyślne): przechwytywane będą wszystkie zapisy przechodzące do deskryptorów plików systemu operacyjnego 1 i 2.

  2. Przechwytywanie na poziomie sys : przechwytywane są tylko zapisy do plików Pythona sys.stdout i sys.stderr. Nie jest wykonywane przechwytywanie zapisów do deskryptorów plików.

pytest -s            # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd  # also point filedescriptors 1 and 2 to temp file

17

Musiałem wydrukować ważne ostrzeżenie o pominiętych testach dokładnie wtedy, gdy PyTestwyciszono dosłownie wszystko .

Nie chciałem oblać testu wysyłającego sygnał, więc włamałem się w następujący sposób:

def test_2_YellAboutBrokenAndMutedTests():
    import atexit
    def report():
        print C_patch.tidy_text("""
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.""")
    if sys.stdout != sys.__stdout__:
        atexit.register(report)

atexitModuł pozwala mi wydrukować rzeczy po PyTest zwolniony strumienie wyjściowe. Wynik wygląda następująco:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /media/Storage/henaro/smyth/Alchemist2-git/sources/C_patch, inifile: 
collected 15 items 

test_C_patch.py .....ssss....s.

===================== 10 passed, 5 skipped in 0.15 seconds =====================
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.
~/.../sources/C_patch$

Wiadomość jest drukowana nawet wtedy, gdy PyTestjest w trybie cichym i nie jest drukowana, jeśli uruchamiasz rzeczy py.test -s, więc wszystko jest już ładnie przetestowane.


1
Idealny do generowania niestandardowych metryk testowych.
z0r


2

Pierwotnie przyszedłem tutaj, aby dowiedzieć się, jak wykonać PyTestwydruk w konsoli VSCode podczas uruchamiania / debugowania testu jednostkowego z tego miejsca. Można to zrobić za pomocą następującej launch.jsonkonfiguracji. Biorąc pod uwagę .venvfolder środowiska wirtualnego.

    "version": "0.2.0",
    "configurations": [
        {
            "name": "PyTest",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "module": "pytest",
            "args": [
                "-sv"
            ],
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.venv",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }
    ]
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.