Bagaimana saya bisa melihat hasil cetak normal dibuat selama menjalankan pytest?

401

Kadang-kadang saya ingin memasukkan beberapa pernyataan cetak ke dalam kode saya, dan melihat apa yang tercetak ketika saya menjalankannya. Cara biasa saya untuk "berolahraga" adalah dengan tes pytest yang ada. Tetapi ketika saya menjalankan ini, saya sepertinya tidak dapat melihat output standar (setidaknya dari dalam PyCharm, IDE saya).

Apakah ada cara sederhana untuk melihat output standar selama menjalankan pytest?

Des
sumber
Hanya pada kegagalan atau selalu?
17
-s menonaktifkan penangkapan per-tes
hpk42
3
@delnan - Saya ingin melihatnya selalu
Des

Jawaban:

51

Dalam komentar terangkat ke jawaban yang diterima , Joe bertanya:

Apakah ada cara untuk mencetak ke konsol DAN menangkap output sehingga terlihat di laporan junit?

Dalam UNIX, ini biasa disebut dengan teeing . Idealnya, teeing daripada menangkap akan menjadi standar py.test. Non-idealnya, baik py.test maupun plugin pihak ketiga yang ada py.test (... yang saya tahu, toh ) mendukung teeing - meskipun Python sepele mendukung teeing out-of-the-box .

Py-patching py.test untuk melakukan sesuatu yang tidak didukung tidak mudah. Mengapa? Karena:

  • Sebagian besar fungsi py.test dikunci di belakang _pytestpaket pribadi yang tidak dimaksudkan untuk diimpor secara eksternal. Mencoba melakukannya tanpa mengetahui apa yang Anda lakukan biasanya menghasilkan pytestpaket publik yang meningkatkan pengecualian yang tidak jelas saat runtime. Terima kasih banyak, py.test. Anda benar-benar memiliki arsitektur yang kuat.
  • Bahkan ketika Anda melakukan mencari cara untuk monyet-patch swasta _pytestAPI dengan cara yang aman, Anda harus melakukannya sebelum menjalankan publik pytestpaket dijalankan oleh eksternal py.testperintah. Anda tidak dapat melakukan ini dalam plugin (mis., conftestModul tingkat atas di suite pengujian Anda). Pada saat py.test malas untuk secara dinamis mengimpor plugin Anda, setiap kelas py.test yang ingin Anda tempelkan kera sudah sejak lama dipakai - dan Anda tidak memiliki akses ke instance itu. Ini menyiratkan bahwa, jika Anda ingin patch monyet Anda diterapkan secara bermakna, Anda tidak dapat lagi menjalankan py.testperintah eksternal dengan aman . Sebagai gantinya, Anda harus membungkus menjalankan perintah itu dengan alat setup kustomtest perintah itu (dalam urutan):
    1. Monkey-patch patch pribadi _pytest.
    2. Memanggil pytest.main()fungsi publik untuk menjalankan py.testperintah.

Ini menjawab monyet-patch py.test -sdan --capture=noopsi untuk menangkap stderr tetapi tidak stdout. Secara default, opsi ini tidak menangkap stderr atau stdout. Ini tidak cukup teeing, tentu saja. Tetapi setiap perjalanan besar dimulai dengan prekuel yang membosankan yang dilupakan semua orang dalam lima tahun.

Kenapa melakukan ini? Sekarang saya akan memberi tahu Anda. Rangkaian uji yang digerakkan oleh py.test saya berisi tes fungsional lambat. Menampilkan tes ini sangat membantu dan meyakinkan, mencegah leycec dari mencapai killall -9 py.testketika tes fungsional lama lainnya gagal melakukan apa pun selama berminggu-minggu. Namun, dengan menampilkan stderr dari tes-tes ini, mencegah py.test melaporkan traceback pengecualian pada kegagalan tes. Yang benar-benar tidak membantu. Karenanya, kami memaksa py.test untuk menangkap stderr tetapi tidak stdout.

Sebelum kita testmembahasnya , jawaban ini mengasumsikan Anda sudah memiliki perintah custom setuptools yang memanggil py.test. Jika tidak, lihat subbagian Integrasi Manual dari halaman Good Practices yang ditulis py.test .

Jangan tidak menginstal pytest-pelari , seorang setuptools pihak ketiga plugin yang menyediakan setuptools kustom testperintah juga memohon py.test. Jika pytest-runner sudah diinstal, Anda mungkin perlu menghapus instalasi paket pip3 itu dan kemudian mengadopsi pendekatan manual yang terhubung ke atas.

Dengan asumsi Anda mengikuti petunjuk dalam Integrasi Manual yang disorot di atas, basis kode Anda sekarang harus berisi PyTest.run_tests()metode. Ubah metode ini menyerupai:

class PyTest(TestCommand):
             .
             .
             .
    def run_tests(self):
        # Import the public "pytest" package *BEFORE* the private "_pytest"
        # package. While importation order is typically ignorable, imports can
        # technically have side effects. Tragicomically, that is the case here.
        # Importing the public "pytest" package establishes runtime
        # configuration required by submodules of the private "_pytest" package.
        # The former *MUST* always be imported before the latter. Failing to do
        # so raises obtuse exceptions at runtime... which is bad.
        import pytest
        from _pytest.capture import CaptureManager, FDCapture, MultiCapture

        # If the private method to be monkey-patched no longer exists, py.test
        # is either broken or unsupported. In either case, raise an exception.
        if not hasattr(CaptureManager, '_getcapture'):
            from distutils.errors import DistutilsClassError
            raise DistutilsClassError(
                'Class "pytest.capture.CaptureManager" method _getcapture() '
                'not found. The current version of py.test is either '
                'broken (unlikely) or unsupported (likely).'
            )

        # Old method to be monkey-patched.
        _getcapture_old = CaptureManager._getcapture

        # New method applying this monkey-patch. Note the use of:
        #
        # * "out=False", *NOT* capturing stdout.
        # * "err=True", capturing stderr.
        def _getcapture_new(self, method):
            if method == "no":
                return MultiCapture(
                    out=False, err=True, in_=False, Capture=FDCapture)
            else:
                return _getcapture_old(self, method)

        # Replace the old with the new method.
        CaptureManager._getcapture = _getcapture_new

        # Run py.test with all passed arguments.
        errno = pytest.main(self.pytest_args)
        sys.exit(errno)

Untuk mengaktifkan monkey-patch ini, jalankan py.test sebagai berikut:

python setup.py test -a "-s"

Stderr tetapi tidak stdout sekarang akan ditangkap. Bagus!

Memperluas patch monyet di atas ke tee stdout dan stderr dibiarkan sebagai latihan untuk pembaca dengan barel penuh waktu luang.

Cecil Curry
sumber
33

Saat menjalankan tes gunakan -sopsi. Semua pernyataan cetak dalam exampletest.pyakan dicetak pada konsol saat tes dijalankan.

py.test exampletest.py -s
Summerfun
sumber
31

Menurut dokumentasi pytest , versi 3 dari pytest dapat menonaktifkan penangkapan sementara dalam tes:

def test_disabling_capturing(capsys):
    print('this output is captured')
    with capsys.disabled():
        print('output not captured, going directly to sys.stdout')
    print('this output is also captured')
Roman Susi
sumber
20

pytest menangkap stdout dari masing-masing tes dan menampilkannya hanya pada kondisi tertentu, bersama dengan ringkasan tes yang dicetak secara default.

Info ringkasan tambahan dapat ditampilkan menggunakan opsi '-r':

pytest -rP

menunjukkan hasil yang ditangkap dari tes yang lulus.

pytest -rx

menunjukkan hasil pengujian gagal yang ditangkap (perilaku default).

Format output lebih cantik dengan -r daripada dengan -s.

Sunthar
sumber
2
Inilah jawaban sebenarnya yang saya cari! Terima kasih. (Setelah stdout datang SETELAH hasil tes diinginkan. Ketika mereka disisipkan, garis yang dicetak kehilangan nilai.)
bossylobster
18

Coba pytest -s -v test_login.pyuntuk info lebih lanjut di konsol.

-v ini singkat --verbose

-s berarti 'nonaktifkan semua pengambilan'



Alex Makarenko
sumber
1
jika Anda menggunakan file pytest.ini, Anda dapat menggunakan: addopts = -s -v python_files = test_login.py
timj98
4

Jika Anda menggunakan PyCharm IDE, maka Anda dapat menjalankan tes individual atau semua tes menggunakan Run toolbar. Jendela Jalankan alat menampilkan keluaran yang dihasilkan oleh aplikasi Anda dan Anda dapat melihat semua pernyataan cetak di sana sebagai bagian dari hasil pengujian.

Gemini Jain
sumber
Apakah Anda tahu cara membuat cetak PyCharm saat tes sedang berjalan? (Alih-alih setelah tes berlalu)
Alexandre Huat
3

pytest --capture=tee-sysbaru-baru ini ditambahkan. Anda dapat menangkap serta melihat output pada stdout / err.

meonstackexchange
sumber
-4

Jawaban lain tidak berhasil. Satu- satunya cara untuk melihat output yang ditangkap menggunakan bendera berikut:

pytest --show-capture all

aaa90210
sumber
6
--show-capture=alladalah nilai default. Menambahkannya tidak mempengaruhi apa pun.
hoefling