Saya perlu menulis tes JUnit untuk aplikasi lama yang dirancang dengan buruk dan sedang menulis banyak pesan kesalahan ke output standar. Ketika getResponse(String request)
metode berperilaku dengan benar, ia mengembalikan respons XML:
@BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
@Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
Tetapi ketika mendapat XML cacat atau tidak mengerti permintaan itu kembali null
dan menulis beberapa hal ke output standar.
Apakah ada cara untuk menegaskan keluaran konsol di JUnit? Untuk menangkap kasus seperti:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
Jawaban:
menggunakan ByteArrayOutputStream dan System.setXXX sederhana:
contoh uji kasus:
Saya menggunakan kode ini untuk menguji opsi baris perintah (menyatakan bahwa -versi keluaran string versi, dll.)
Sunting: Versi sebelumnya dari jawaban ini dipanggil
System.setOut(null)
setelah tes; Ini adalah penyebab yang dirujuk oleh komentator NullPointerExceptions.sumber
NullPointerException
dalam tes lain setelah menetapkan aliran kesalahan nol seperti yang disarankan di atas (dalamjava.io.writer(Object)
, dipanggil secara internal oleh validator XML). Saya akan menyarankan sebaliknya menyimpan yang asli di bidang:oldStdErr = System.err
dan mengembalikan ini dalam@After
metode.Saya tahu ini adalah utas lama, tetapi ada perpustakaan yang bagus untuk melakukan ini:
Aturan Sistem
Contoh dari dokumen:
Ini juga akan memungkinkan Anda untuk menjebak
System.exit(-1)
dan hal-hal lain yang perlu diuji oleh alat baris perintah.sumber
Alih-alih mengarahkan
System.out
, saya akan refactor kelas yang menggunakanSystem.out.println()
dengan melewati aPrintStream
sebagai kolaborator dan kemudian menggunakanSystem.out
dalam produksi dan Mata-Mata Uji dalam tes. Yaitu, gunakan Dependency Injection untuk menghilangkan penggunaan langsung dari arus keluaran standar.Dalam produksi
Dalam Tes
Diskusi
Dengan cara ini kelas yang diuji dapat diuji dengan refactoring sederhana, tanpa perlu pengalihan tidak langsung dari output standar atau penyadapan yang tidak jelas dengan aturan sistem.
sumber
ConsoleWriter
adalah subjek ujian,Anda dapat mengatur aliran cetak System.out melalui setOut () (dan untuk
in
danerr
). Bisakah Anda mengarahkan ini ke aliran cetak yang merekam ke string, dan kemudian memeriksanya? Itu akan tampak sebagai mekanisme paling sederhana.(Saya akan menganjurkan, pada tahap tertentu, mengonversi aplikasi ke beberapa kerangka logging - tapi saya curiga Anda sudah mengetahui hal ini!)
sumber
Sedikit keluar dari topik, tetapi jika beberapa orang (seperti saya, ketika saya pertama kali menemukan utas ini) mungkin tertarik untuk menangkap keluaran log melalui SLF4J, pengujian umum JUnit
@Rule
mungkin membantu:Penafian :
log4j
,log4j2
danlogback
tersedia saat ini, tetapi saya senang menambahkan lebih banyak.sumber
@ dfa jawabannya bagus, jadi saya mengambil langkah lebih jauh untuk memungkinkan untuk menguji blok ouput.
Pertama saya buat
TestHelper
dengan metodecaptureOutput
yang menerima kelas yang menjengkelkanCaptureTest
. Metode captureOutput melakukan pekerjaan pengaturan dan menghancurkan aliran output. Ketika pelaksanaanCaptureOutput
'stest
metode ini disebut, memiliki akses ke output menghasilkan untuk blok tes.Sumber untuk TestHelper:
Perhatikan bahwa TestHelper dan CaptureTest didefinisikan dalam file yang sama.
Kemudian dalam pengujian Anda, Anda dapat mengimpor tangkapan statis. Berikut ini contoh menggunakan JUnit:
sumber
Jika Anda menggunakan Spring Boot (Anda menyebutkan bahwa Anda sedang bekerja dengan aplikasi lama, jadi Anda mungkin tidak melakukannya tetapi mungkin berguna bagi orang lain), maka Anda dapat menggunakan org.springframework.boot.test.rule.OutputCapture dengan cara berikut:
sumber
Berdasarkan jawaban @ dfa dan jawaban lain yang menunjukkan cara menguji System.in , saya ingin membagikan solusi saya untuk memberikan input ke suatu program dan menguji hasilnya.
Sebagai referensi, saya menggunakan JUnit 4.12.
Katakanlah kita memiliki program ini yang hanya mereplikasi input ke output:
Untuk mengujinya, kita dapat menggunakan kelas berikut:
Saya tidak akan menjelaskan banyak, karena saya percaya kode tersebut dapat dibaca dan saya mengutip sumber saya.
Ketika JUnit berjalan
testCase1()
, ia akan memanggil metode helper sesuai urutannya:setUpOutput()
, karena@Before
penjelasannyaprovideInput(String data)
, dipanggil daritestCase1()
getOutput()
, dipanggil daritestCase1()
restoreSystemInputOutput()
, karena@After
penjelasannyaSaya tidak menguji
System.err
karena saya tidak membutuhkannya, tetapi harus mudah diimplementasikan, mirip dengan pengujianSystem.out
.sumber
Anda tidak ingin mengarahkan aliran system.out karena itu mengalihkan untuk SELURUH JVM. Apa pun yang berjalan di JVM bisa kacau. Ada cara yang lebih baik untuk menguji input / output. Lihatlah ke bertopik / mengolok-olok.
sumber
Contoh lengkap JUnit 5 untuk menguji
System.out
(ganti bagian ketika):sumber
Anda tidak dapat langsung mencetak dengan menggunakan system.out.println atau menggunakan logger api saat menggunakan JUnit . Tetapi jika Anda ingin memeriksa nilai apa pun maka Anda bisa menggunakannya
Ini akan melempar kesalahan pernyataan di bawah ini:
Nilai Anda harus 21,92, Sekarang jika Anda akan menguji menggunakan nilai ini seperti di bawah ini test case Anda akan lulus.
sumber
untuk keluar
untuk err
sumber
@Rule
, daripada melakukannya inline dalam pengujian Anda. Khususnya, jika pernyataan Anda gagal,System.setOut/Err
panggilan kedua tidak akan tercapai.