Saya sedang menulis tes untuk fungsi seperti berikut:
def foo():
print 'hello world!'
Jadi ketika saya ingin menguji fungsi ini kodenya akan seperti ini:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
Tetapi jika saya menjalankan nosetests dengan parameter -s, pengujian akan macet. Bagaimana saya bisa menangkap output dengan modul unittest atau nose?
python
unit-testing
nosetests
python-nose
Pedro Valencia
sumber
sumber
with mock.patch('sys.stdout', new_callable=StringIO.StringIO):
pypi.python.org/pypi/mockJawaban:
Saya menggunakan manajer konteks ini untuk menangkap keluaran. Ini pada akhirnya menggunakan teknik yang sama seperti beberapa jawaban lainnya dengan mengganti sementara
sys.stdout
. Saya lebih suka manajer konteks karena ini membungkus semua pembukuan menjadi satu fungsi, jadi saya tidak perlu menulis ulang kode coba-akhirnya, dan saya tidak perlu menulis fungsi penyiapan dan pembongkaran hanya untuk ini.Gunakan seperti ini:
Selanjutnya, karena status keluaran asli dipulihkan setelah keluar dari
with
blok, kita dapat mengatur blok penangkapan kedua dalam fungsi yang sama seperti yang pertama, yang tidak mungkin menggunakan fungsi pengaturan dan pembongkaran, dan menjadi bertele-tele saat menulis coba-akhirnya memblokir secara manual. Kemampuan itu berguna saat tujuan pengujian adalah untuk membandingkan hasil dari dua fungsi relatif satu sama lain daripada dengan beberapa nilai yang telah dihitung sebelumnya.sumber
TypeError: unicode argument expected, got 'str'
(jenis yang diteruskan untuk dicetak (str / unicode) tidak relevan).from io import BytesIO as StringIO
dan di python 3 sajafrom io import StringIO
. Sepertinya memperbaiki masalah dalam pengujian saya, saya pikir.strip()
yangunicode
dikembalikan dariStringIO.getvalue()
?sys
. Dengan pernyataan import Anda, Anda membuat variabel lokal bernamastderr
yang menerima salinan nilai dalamsys.stderr
. Perubahan satu tidak tercermin di yang lain.Jika Anda benar-benar ingin melakukan ini, Anda dapat menetapkan kembali sys.stdout selama pengujian.
Jika saya menulis kode ini, bagaimanapun, saya lebih suka memberikan
out
parameter opsional kefoo
fungsi.Maka tesnya jauh lebih sederhana:
sumber
StringIO
kelas sekarang harus diimpor dariio
modul.from io import StringIO
bekerja di python 2.6+.from io import StringIO
python 2, Anda mendapatkanTypeError: unicode argument expected, got 'str'
saat mencetak.with redirect_stdout(out):
saved_stdout = sys.stdout
, Anda selalu memiliki referensi ajaib untuk inisys.__stdout__
, misalnya, Anda hanya perlusys.stdout = sys.__stdout__
dalam pembersihan.Sejak versi 2.7, Anda tidak perlu lagi menetapkan kembali
sys.stdout
, ini disediakan melaluibuffer
flag . Selain itu, ini adalah perilaku default nosetest.Berikut ini contoh yang gagal dalam konteks non buffer:
Anda dapat mengatur buffer melalui
unit2
bendera baris perintah-b
,--buffer
atau dalamunittest.main
opsi. Kebalikannya dicapai melaluinosetest
bendera--nocapture
.sumber
--nocapture
; khususnya, jika flag ini diset, mode buffer akan dinonaktifkan. Jadi, Anda memiliki opsi untuk dapat melihat keluaran di terminal, atau dapat menguji apakah keluarannya sesuai dengan yang diharapkan.Banyak dari jawaban ini gagal untuk saya karena Anda tidak bisa
from StringIO import StringIO
menggunakan Python 3. Berikut cuplikan kerja minimum berdasarkan komentar @ naxa dan Python Cookbook.sumber
Di python 3.5 Anda dapat menggunakan
contextlib.redirect_stdout()
danStringIO()
. Berikut modifikasi pada kode Andasumber
redirect_stdout()
danredirect_stderr()
mengembalikan argumen masukan mereka. Jadi,with contextlib.redirect_stdout(StringIO()) as temp_stdout:
berikan Anda semua dalam satu baris. Diuji dengan 3.7.1.Saya baru saja belajar Python dan mendapati diri saya berjuang dengan masalah yang mirip dengan masalah di atas dengan pengujian unit untuk metode dengan keluaran. Uji unit kelulusan saya untuk modul foo di atas akhirnya terlihat seperti ini:
sumber
sys.stdout.getvalue().strip()
dan tidak menipu dibandingkan dengan\n
:)from io import StringIO
Tes menulis sering kali menunjukkan kepada kita cara yang lebih baik untuk menulis kode kita. Mirip dengan jawaban Shane, saya ingin menyarankan cara lain untuk melihat ini. Apakah Anda benar-benar ingin menegaskan bahwa program Anda mengeluarkan string tertentu, atau hanya ia membangun string tertentu untuk keluaran? Ini menjadi lebih mudah untuk diuji, karena kita mungkin dapat berasumsi bahwa
print
pernyataan Python melakukan tugasnya dengan benar.Maka tes Anda sangat sederhana:
Tentu saja, jika Anda benar-benar perlu menguji keluaran aktual program Anda, abaikan saja. :)
sumber
foo()
tidak melakukan apapun kecuali memanggil pernyataan cetak, itu mungkin tidak menjadi masalah.Berdasarkan jawaban Rob Kennedy, saya menulis versi manajer konteks berbasis kelas untuk menyangga keluaran.
Penggunaannya seperti:
Berikut implementasinya:
sumber
Atau pertimbangkan untuk menggunakan
pytest
, ia memiliki dukungan built-in untuk menegaskan stdout dan stderr. Lihat dokumensumber
Baik n611x007 dan Noumenon sudah menyarankan penggunaan
unittest.mock
, tetapi jawaban ini menyesuaikan Acumenus untuk menunjukkan bagaimana Anda dapat dengan mudah membungkusunittest.TestCase
metode untuk berinteraksi dengan tiruanstdout
.sumber
Membangun semua jawaban luar biasa di utas ini, inilah cara saya menyelesaikannya. Saya ingin menyimpannya sebagai stok. Aku ditambah mekanisme uji unit menggunakan
setUp()
untuk menangkapsys.stdout
dansys.stderr
, menambahkan API menegaskan baru untuk memeriksa nilai-nilai yang diambil terhadap nilai yang diharapkan dan kemudian mengembalikansys.stdout
dansys.stderr
padatearDown(). I did this to keep a similar unit test API as the built-in
unittestAPI while still being able to unit test values printed to
sys.stdoutor
sys.stderr`.Saat unit test dijalankan, hasilnya adalah:
sumber