Masuk dalam tes pytest

90

Saya ingin meletakkan beberapa pernyataan logging dalam fungsi pengujian untuk memeriksa beberapa variabel status.

Saya memiliki cuplikan kode berikut:

import pytest,os
import logging

logging.basicConfig(level=logging.DEBUG)
mylogger = logging.getLogger()

#############################################################################

def setup_module(module):
    ''' Setup for the entire module '''
    mylogger.info('Inside Setup')
    # Do the actual setup stuff here
    pass

def setup_function(func):
    ''' Setup for test functions '''
    if func == test_one:
        mylogger.info(' Hurray !!')

def test_one():
    ''' Test One '''
    mylogger.info('Inside Test 1')
    #assert 0 == 1
    pass

def test_two():
    ''' Test Two '''
    mylogger.info('Inside Test 2')
    pass

if __name__ == '__main__':
    mylogger.info(' About to start the tests ')
    pytest.main(args=[os.path.abspath(__file__)])
    mylogger.info(' Done executing the tests ')

Saya mendapatkan output berikut:

[bmaryada-mbp:/Users/bmaryada/dev/platform/main/proto/tests/tpch $]python minitest.py
INFO:root: About to start the tests 
======================================================== test session starts =========================================================
platform darwin -- Python 2.6.2 -- pytest-2.0.0
collected 2 items 

minitest.py ..

====================================================== 2 passed in 0.01 seconds ======================================================
INFO:root: Done executing the tests 

Perhatikan bahwa hanya pesan logging dari '__name__ == __main__'blok yang dikirim ke konsol.

Apakah ada cara untuk memaksa pytestmengeluarkan logging ke konsol dari metode pengujian juga?

superselector
sumber
3
Anda mungkin melihat jawaban ini , yang diposting oleh pembuat py.test. Dia menyarankan plugin pytest yang memberikan tingkat keserbagunaan tinggi.
chb

Jawaban:

30

Berfungsi untuk saya, inilah output yang saya dapatkan: [snip -> contoh salah]

Edit: Tampaknya Anda harus meneruskan -sopsi ke py.test sehingga tidak akan menangkap stdout. Di sini (py.test tidak diinstal), itu sudah cukup untuk digunakan python pytest.py -s pyt.py.

Untuk kode Anda, yang Anda butuhkan adalah untuk lulus -sdalam argske main:

 pytest.main(args=['-s', os.path.abspath(__file__)])

Lihat dokumentasi py.test tentang menangkap keluaran .

TryPyPy
sumber
Maaf. Saya menempelkan kode dengan tergesa-gesa. Hapus 'assert 0 == 1' dari fungsi 'test_one' untuk mengetahui 'masalah'. Hanya ketika ada beberapa kegagalan (yang saya paksa dengan pernyataan palsu), py.test tampaknya mencetak informasi logging.
superselector
Tidak masalah, saya menemukan cara memperbaiki pada baris perintah, mencari cara terprogram.
TryPyPy
1
Anda juga bisa mengarahkan keluaran logging ke beberapa file alih-alih stderr implisit default.
hpk42
@superselector hpk42 adalah orang py.test, dengarkan. IIUC, dalam kode Anda itu akan logging.basicConfig(filename="somelog.txt", level=logging.DEBUG).
TryPyPy
115

Sejak versi 3.3, pytestmendukung live logging, yang berarti bahwa semua catatan log yang dikeluarkan dalam pengujian akan segera dicetak ke terminal. Fitur ini didokumentasikan di bawah bagian Live Logs . Live logging dinonaktifkan secara default; untuk mengaktifkannya, setel log_cli = 1di pytest.inikonfigurasi 1 . Live logging mendukung pemancaran ke terminal dan file; opsi yang relevan memungkinkan penyesuaian catatan:

terminal:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

mengajukan:

  • log_file
  • log_file_level
  • log_file_format
  • log_file_date_format

Catatan : log_clibendera tidak bisa dilewatkan dari baris perintah dan harus disetel masuk pytest.ini. Semua opsi lain dapat diteruskan dari baris perintah atau disetel di file konfigurasi. Seperti yang ditunjukkan oleh Kévin Barré dalam komentar ini , menimpa opsi ini dari baris perintah dapat dilakukan melalui -o/--overrideopsi tersebut. Jadi, alih-alih mendeklarasikan log_climasuk pytest.ini, Anda cukup memanggil:

$ pytest -o log_cli=true ...

Contoh

File pengujian sederhana yang digunakan untuk mendemonstrasikan:

# test_spam.py

import logging

LOGGER = logging.getLogger(__name__)


def test_eggs():
    LOGGER.info('eggs info')
    LOGGER.warning('eggs warning')
    LOGGER.error('eggs error')
    LOGGER.critical('eggs critical')
    assert True

Seperti yang Anda lihat, tidak diperlukan konfigurasi tambahan; pytestakan mengatur logger secara otomatis, berdasarkan opsi yang ditentukan pytest.iniatau diteruskan dari baris perintah.

Live logging ke terminal, INFOlevel, keluaran mewah

Konfigurasi di pytest.ini:

[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S

Menjalankan tes:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
2018-08-01 14:33:20 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:33:20 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:33:20 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:33:20 [CRITICAL] eggs critical (test_spam.py:10)
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

Live logging ke terminal dan file, hanya pesan & CRITICALlevel di terminal, keluaran mewah dalam pytest.logfile

Konfigurasi di pytest.ini:

[pytest]
log_cli = 1
log_cli_level = CRITICAL
log_cli_format = %(message)s

log_file = pytest.log
log_file_level = DEBUG
log_file_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_file_date_format=%Y-%m-%d %H:%M:%S

Uji coba:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
eggs critical
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

$ cat pytest.log
2018-08-01 14:38:09 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:38:09 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:38:09 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:38:09 [CRITICAL] eggs critical (test_spam.py:10)

1 Meskipun Anda dapat mengonfigurasi pytestdi setup.cfgbawah [tool:pytest]bagian ini, jangan tergoda untuk melakukannya saat Anda ingin menyediakan format logging langsung kustom. Alat lain yang membaca setup.cfgmungkin memperlakukan hal-hal seperti %(message)sinterpolasi string dan gagal. Gunakan pytest.iniuntuk menghindari kesalahan.

hoefling
sumber
17
Tentang catatan yang log_cliharus ada di pytest.ini , sepertinya Anda dapat menggunakan -oopsi untuk mengganti nilai dari baris perintah. pytest -o log_cli=true --log-cli-level=DEBUGbekerja untuk saya.
Kévin Barré
@ KévinBarré komentar yang sangat bagus dan petunjuk yang sangat berguna secara umum, terima kasih! Memperbarui jawabannya.
hoefling
Ini pasti jawaban yang benar saat menggunakan logging. Meskipun saya suka membedakan log yang ada di dalam pengujian, dan log yang ada di dalam sistem yang diuji yang harus dipertimbangkan secara terpisah.
CMCDragonkai
@CMCDragonkai sayangnya, pytestagak terbatas dalam hal itu. Namun, ini harus bisa dilakukan dengan konfigurasi logging khusus untuk pengujian di aplikasi Anda; matikan propagasi di logger Anda dan tambahkan "penangan pengujian" yang mencatat log ke file yang ditentukan. Dengan cara ini, pytesthanya catatan log yang berasal dari pengujian, sedangkan handler kustom menangani log SuT.
hoefling
1
@OfekAgmon jika Anda ingin menyimpan pytestoutput, Anda dapat menggunakan --result-logargumen (meskipun catatan ini sudah usang, berikut adalah alternatifnya ). Anda tidak dapat menyimpan pytestkeluaran dan keluaran pencatatan langsung dalam file yang sama.
hoefling