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):
- Monkey-patch patch pribadi
_pytest.
- 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.