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
_pytest
paket pribadi yang tidak dimaksudkan untuk diimpor secara eksternal. Mencoba melakukannya tanpa mengetahui apa yang Anda lakukan biasanya menghasilkan pytest
paket 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
_pytest
API dengan cara yang aman, Anda harus melakukannya sebelum menjalankan publik pytest
paket dijalankan oleh eksternal py.test
perintah. Anda tidak dapat melakukan ini dalam plugin (mis., conftest
Modul 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.test
perintah eksternal dengan aman . Sebagai gantinya, Anda harus membungkus menjalankan perintah itu dengan alat setup kustomtest
perintah itu (dalam urutan):
- Monkey-patch patch pribadi
_pytest
.
- Memanggil
pytest.main()
fungsi publik untuk menjalankan py.test
perintah.
Ini menjawab monyet-patch py.test -s
dan --capture=no
opsi 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.test
ketika 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 test
membahasnya , 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 test
perintah 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.