Nunit: Menangkap AssertionException gagal tes sejak 3.10.

Dibuat pada 14 Mar 2018  ·  22Komentar  ·  Sumber: nunit/nunit

````
mencoba
{
Assert.True(salah, "pesan kesalahan");
}
tangkap (AssertionException e)
{
Trace.WriteLine("Abaikan.");
}

        Trace.WriteLine("Test Passed");

````

Di Nunit 3.9.0 tes ini berhasil dan ditandai sebagai lulus di test explorer saat dijalankan dari visual studio test explorer. Di Nunit 3.10 testcase ditandai sebagai gagal dalam tinjauan penjelajah pengujian. Garis jejak terakhir dijalankan di kedua versi.

question

Komentar yang paling membantu

@fluffynuts Dulu, ketika saya pertama kali menulis Assert.Catch itu hanya menangkap pengecualian apa pun dan tidak menghasilkan kesalahan jika tidak ada pengecualian yang dilemparkan. Sayangnya, itu berubah dan kami tidak lagi memiliki padanan "netral" dari Assert.Throws . Anda bisa menulis satu, namun. Ini adalah versi yang belum diuji berdasarkan kode di Assert.Throws . Itu hanya menangani kode sinkron tetapi Anda dapat memperluasnya dengan mudah untuk async menggunakan kode tambahan dari Assert.Throws .

```C#
public static void Exception SafelyCatchAnNUnitException (kode TestDelegate)
{
Pengecualian catchException = null;

using (new TestExecutionContext.IsolatedContext())
{
    try
    {
        code();
    }
    catch (Exception ex)
    {
        caughtException = ex;
    }

    return caughtException;
}

}
```

Metode ini akan mengembalikan pengecualian apa pun yang dilemparkan, membersihkan sisa-sisa kesalahan yang ditinggalkan oleh metode penegasan NUnit. Jika tidak ada pengecualian yang dilemparkan, ia mengembalikan nol.

Dimungkinkan juga untuk menggunakan IsolatedContext() pada tingkat yang lebih tinggi dalam kode Anda untuk mengambil hasil pengujian yang sebenarnya dari kode tersebut. Itu akan memungkinkan Anda untuk menguji sepenuhnya pada tingkat hasil tes, tanpa referensi ke pengecualian. Saya telah memikirkan untuk menulis perpustakaan untuk jenis pengujian ini, yang menurut saya akan lebih unggul daripada cara NUnit saat ini melakukan pengujiannya sendiri.

Semua 22 komentar

Pengujian Anda menguji dua proposisi tentang cara kerja NUnit:

  1. Bahwa semua kegagalan pernyataan melempar AssertionException.
  2. Menangkap pengecualian itu mencegah kesalahan dilaporkan.

Seperti yang terjadi, pernyataan pertama sebagian besar benar tetapi tidak berlaku dalam beberapa blok pernyataan atau saat mengeluarkan peringatan. Yang kedua tidak benar sama sekali. Pada saat Anda menangkap pengecualian, kegagalan telah dicatat. Ini adalah perubahan dalam perilaku internal NUnit, hanya dapat diamati jika Anda menangkap pengecualian ini. Saya, misalnya, telah memberi tahu orang-orang untuk tidak bergantung pada perilaku itu selama bertahun-tahun, karena itu hanya kebetulan implementasi.

Saya menyadari bahwa kode sampel Anda hanya dimaksudkan untuk menunjukkan masalah yang Anda lihat. Bisakah Anda memberikan contoh tentang apa yang sebenarnya Anda coba lakukan dalam menangkap pengecualian? Saya cukup yakin kami dapat membantu Anda menemukan solusi yang lebih baik.

Terima kasih telah menghubungi saya kembali dalam waktu sesingkat itu. Saya menggunakan mekanisme ketika hal-hal masih terkelupas. Jadi terkadang perangkat lunak tidak berfungsi dengan baik. Dalam kasus ini saya melaporkan ini ke devs. Sementara itu, kami memperluas pengujian untuk mengatasi perilaku tidak stabil ini. Jadi tes lulus bukannya gagal pada masalah ini.

Kami mencoba menggunakan metode Warn.If() untuk ini, namun ini menetapkan hasilnya ke "Test Skipped" di test explorer. Ini menyebabkan kegagalan pelaporan karena pengujian tidak dilewati sama sekali. Jadi kami memilih untuk menerapkan pernyataan catch dan melacak peringatan. Saya tahu, tidak diinginkan tetapi itu bekerja dengan cukup baik. Setidaknya sampai pembaruan terakhir.

Saya ingin tahu apakah perubahan ini disengaja, dalam hal ini saya tahu saya harus mengubah banyak hal.

Warn.If berfungsi dengan baik ... __except__ di bawah Test Explorer. Masalahnya adalah Test Explorer tahu tentang lulus dan gagal, tetapi tidak memperingatkan. Kami harus menerjemahkan hasil peringatan kami menjadi sesuatu yang dapat mereka pahami sampai mereka menerapkan status hasil peringatan. FWIW kami memiliki masalah yang sama dengan status hasil tidak meyakinkan kami.

Perubahan yang kami lakukan memang disengaja dan sudah direncanakan sejak lama. Kami tidak ingin terlalu bergantung pada pengecualian dan kami ingin melaporkan hasil penegasan - termasuk yang lulus pada akhirnya - dengan cara tertentu yang tidak menghentikan pengujian. Kami telah membuat beberapa perubahan untuk mengurangi dampaknya bagi pengguna seperti Anda, tetapi yang satu ini tampaknya tidak memiliki kemungkinan mitigasi.

Jika Anda memiliki tes terkelupas, standar selama bertahun-tahun adalah Mengabaikannya. Sayangnya, banyak tim "mengabaikan tes yang diabaikan," dalam hal ini bukan pilihan yang baik. Jika Anda dapat melatih tim Anda untuk menanggapi peringatan dengan serius - bahkan hampir sama seriusnya dengan kesalahan dan kegagalan - maka Anda dapat menggunakan status peringatan untuk menyoroti kelemahan. Kemungkinan lain adalah menggunakan Abaikan dengan properti Hingga, sehingga berubah menjadi kegagalan jika tidak diperbaiki pada tanggal tertentu.

BTW, ketika saya melatih tim, saya biasanya memiliki Tampilan Besar Terlihat yang terus diperbarui dari tes yang diabaikan. Di sebagian besar tim, semua orang tahu siapa yang bertanggung jawab atas apa, jadi tidak perlu benar-benar memanggil orang yang bertanggung jawab atas tes tidak stabil itu. Mereka cenderung diperbaiki ketika semua orang melihat masalahnya.

@svanimpelen sudahkah Anda mencoba menggunakan atribut Retry untuk tes yang tidak stabil? Ini akan memungkinkan Anda untuk menjalankannya beberapa kali agar mereka lulus.

Adapun peringatan yang mengakibatkan tes yang dilewati di explorer, kami telah berbicara dengan tim studio visual tentang memungkinkan kami untuk menentukan lebih banyak status hasil daripada jumlah terbatas dari MSTest yang saat ini mereka dukung. Mereka menyukai ide itu, jadi semoga kita akan melihat perbaikan di sana di masa depan. Sampai saat itu Anda harus menderita dengan dilewati. Yang mengatakan, melewatkan hasil dalam peringatan. Saya akan menganggap Anda ingin peringatan menjadi sangat jelas

Begitu banyak metode kami yang mendokumentasikan bahwa API melempar AssertionException saat gagal:

https://github.com/nunit/nunit/blob/d03e93c8f25170a8ff48e80863a3fe6fd294613a/src/NUnitFramework/framework/Assert.That.cs#L40 -L43

Bukankah dokumentasi ini, ditambah perilaku lama NUnit, merupakan perubahan besar pada 3.10?
Kecuali saya melewatkan sesuatu, setidaknya kita harus menghapus dokumen yang sekarang salah.

Saya setuju bahwa dokumentasi dapat menyesatkan sekarang karena kami telah memperkenalkan beberapa blok pernyataan. Yang mengatakan, AssertionException masih dilemparkan dalam kasus ini, perbedaannya adalah bahwa tes sekarang dilaporkan sebagai kegagalan di Visual Studio meskipun pengecualian telah ditangkap. Saya tidak melihat itu sebagai perubahan yang menghancurkan. Pengguna mengandalkan perilaku tidak berdokumen yang kebetulan berhasil. Bagi saya, itu tidak berbeda dengan pengguna yang mengandalkan fakta bahwa tes dijalankan dalam urutan abjad untuk memesan tes mereka.

Kami mungkin harus memperbarui dokumentasi. Kami dapat menghapus informasi tentang melempar pengecualian dan sebagai gantinya hanya menyatakan bahwa kondisi yang salah gagal dalam pengujian. Dan/Atau, kita dapat menyatakan bahwa pengecualian tidak dilemparkan ke dalam blok multi-pernyataan? Secara pribadi, saya pikir jenis pengecualian yang dilemparkan adalah detail internal, jadi saya lebih suka opsi pertama.

Saya pikir itu benar. Jika penggunaan pengecualian akan didokumentasikan di mana saja, itu bisa di bagian wiki di internal.

Ketika dokumentasi metode mengatakan pengecualian akan dilemparkan, saya pikir itu dengan tegas mengatakan bahwa pengecualian dapat ditangkap di situs panggilan. C# tidak memeriksa pengecualian dan dokumen XML adalah cara kami mengomunikasikan bagian dari kontrak metode tersebut. Karena sejauh yang saya ketahui bahasa "melempar X" selalu berarti metode tidak menangkapnya, saya masih agak khawatir bahwa orang lain telah mengambilnya. Mungkin catatan perubahan yang melanggar di wiki berada di sisi yang aman?

Saya suka ide untuk menghapus semua referensi ke AssertionException dari dokumen XML dan membuat halaman wiki yang memperingatkan orang untuk tidak menggunakan AssertionException.

Jika menangkap AssertionException selalu merupakan bug, dapatkah kita mempertimbangkan untuk menjadikan tipe itu sebagai internal?

@jnm2.

Saya setuju dengan Anda tentang pentingnya dokumen XML tetapi faktanya adalah bahwa dokumen tersebut __bukan__ bagaimana kami telah mengomunikasikan bagian dari kontrak hingga sekarang. Saya benar-benar berpikir Anda mungkin orang pertama yang menyarankannya dan saya pikir itu ide yang bagus.

Tapi saya pikir Anda harus menyadari bahwa mulai memikirkan mereka seperti itu akan melibatkan perubahan banyak komentar yang salah! Saya tidak berpikir kita dapat memperlakukan setiap perubahan dokumen ini sebagai perubahan yang melanggar. Berdasarkan kasus per kasus, kami dapat memperlakukan setiap perubahan perilaku yang mendasarinya sebagai pelanggaran, tetapi itu berbeda. Perubahan dokumen tidak boleh melanggar.

Ini memunculkan pertanyaan tentang apa yang harus ada dalam daftar perubahan yang melanggar. Jika saya telah memahami komentar Anda sebelumnya, saya pikir Anda cenderung ingin mendokumentasikan apa pun yang dapat merusak pengguna mana pun. Saya lebih suka mendokumentasikan hal-hal yang kami yakini akan merusak banyak pengguna.

Inilah cara saya melihat perbedaannya - orang lain mungkin tidak setuju... Mendokumentasikan __segala sesuatu yang mungkin rusak__ berbau seperti CYA bagi saya, seperti jenis CYA yang kadang-kadang dinikmati manajemen ketika mereka fokus pada siapa yang disalahkan atas kegagalan daripada mencegah kegagalan itu sendiri. JIKA kita mendokumentasikan semuanya, maka kita bisa mengatakan... "Lihat, kita tercakup." Jika kami hanya mendokumentasikan apa yang kami anggap penting, maka kami berisiko salah dan harus meminta maaf, tetapi kami memberi pengguna rata-rata lebih mudah untuk memahami serangkaian perubahan. Saya lebih suka yang terakhir.

Ada kalanya aman untuk menangkap pengecualian pernyataan. Misalnya, saya membuat perubahan beberapa waktu lalu sehingga akan tetap aman saat menjalankan tes secara langsung, tanpa TestExecutionContext yang terlibat. Jika Anda membuat pengecualian internal, maka Anda melanggarnya. Sebenarnya, saya senang untuk memecahkannya, tetapi tim setuju bahwa kami tidak boleh jadi saya memperbaikinya. Anda hanya perlu memutuskan apa yang ingin Anda hancurkan. Perbaikan itu __not__ menangani masalah saat ini, yang berkaitan dengan menangkap pengecualian di dalam pengujian itu sendiri, bukan dalam kode yang memanggil metode.

Menangkap AssertionException dalam pengujian adalah apa yang saya sebut "bau" klasik. Ini mungkin salah, tetapi Anda harus melihat kasus khusus untuk mengetahuinya. Saya akan memberi tahu pengguna "Menangkap AssertionException kemungkinan besar merupakan kesalahan, kecuali Anda memiliki pengetahuan terperinci tentang internal NUnit. Untuk memastikan perilaku yang tepat, Anda tidak boleh mencoba mengubah hasil pengujian dan harus menampilkan kembali pengecualian setelah melakukan apa pun yang Anda ingin lakukan dengan itu." Namun, saya masih tidak berpikir info seperti itu termasuk dalam dokumen XML atau dokumen pengguna umum. Saya akan meletakkannya sebagai halaman di bagian internal.

BTW, pengalaman masa lalu saya adalah bahwa mendokumentasikan sesuatu dan kemudian memberi tahu orang-orang untuk tidak menggunakannya mengarah pada peningkatan penggunaan. 😄

Poin bagus, terima kasih! Saya pikir saya berpikir sebagian dalam hal CYA. Ada elemen lain juga, yaitu sebagai konsumen perpustakaan, saya pribadi akan menghargai diberitahu setiap perubahan yang melanggar sehingga saya dapat mencari asumsi buruk dalam kode saya sendiri. Terutama dengan perubahan seperti ini yang tidak diperhatikan oleh kompiler. Karena saya akan menghargai itu, saya memproyeksikannya ke pengguna kami sampai batas tertentu.

Haruskah kita memulai masalah baru untuk melacak perbaikan dokumen?

Mengapa baru?

Judulnya tampak seperti sesuatu yang kami tutup sebagai pertanyaan yang dijawab daripada diperbaiki. Apakah kami biasanya mengubah judul dan menggunakan masalah ini untuk melacak perubahan dokumen?

Apa yang biasanya saya lakukan adalah meninjau masalah dan mengklasifikasikannya... dalam hal ini sebagai masalah dokumentasi. Diakui, kami telah menghabiskan waktu yang sangat lama untuk membahasnya sebagai kemungkinan bug terlebih dahulu. Ini adalah pertanyaan administrasi proyek, sungguh, dan di luar lingkup saya.

Apa yang saya katakan, adalah melakukan sesuatu yang logis dan konsisten. Menutup ini sebagai bukan bug adalah pilihan. Itu memisahkan keluhan dari solusi, namun. Menulis komentar penjelasan saat Anda mengklasifikasikan ulang sebagai bug dokumen dan mungkin mengedit judul menyimpan solusi dengan keluhan. Bagaimanapun, judul masalah masalah Selesai berakhir di catatan rilis, jadi itu harus ekspresif dari apa yang terjadi.

Bisakah Anda memberikan contoh tentang apa yang sebenarnya Anda coba lakukan dalam menangkap pengecualian? Saya cukup yakin kami dapat membantu Anda menemukan solusi yang lebih baik.

Saat ini saya menghadapi masalah yang sama sejak pengujian saya mulai gagal setelah memutakhirkan ke 3.10. Sekarang inilah masalah saya:
Saya memiliki metode pernyataan pengujian khusus. Mereka secara internal memanggil NUnit.Assert. Saya menguji metode pernyataan ini untuk memastikan mereka benar-benar gagal ketika saya berharap mereka gagal.
Saat ini pengujian saya menangkap AssertionException untuk memverifikasi metode pernyataan khusus akan menyebabkan pengujian gagal, tetapi setelah memutakhirkan semua pengujian tersebut mulai gagal karena alasan di atas.

Apa cara yang disarankan untuk menguji mereka dengan 3.10?

Terima kasih.

Pendekatan paling sederhana adalah menggunakan Assert.Throws untuk menangkap pengecualian daripada melakukannya sendiri. Assert.Throws memahami internal NUnit dan memastikan bahwa kegagalan tidak dilaporkan.

Saya melihat ini di notifikasi saya beberapa hari yang lalu dan tidak terlalu memikirkannya. Namun, memperbarui proyek perpustakaan saya, yang melakukan "Menegaskan.Itu" di dalam logikanya (ini adalah kerangka kerja pembantu pengujian -- khususnya untuk menyediakan cara mudah untuk menguji kegigihan EF saat mengkodekan konteks dan entitas EF dengan tangan dan mengkodekan database yang sesuai migrasi dengan tangan (atau dengan sesuatu seperti FluentMigrator) -- jadi, dengan kata lain, itu seharusnya melakukan pernyataan atas nama penelepon), saya sekarang mendapatkan tes yang gagal di tempat yang tidak seharusnya -- satu tes khususnya adalah menegaskan bahwa kondisi tertentu harus menyebabkan kegagalan pengujian -- yang memang demikian, tetapi karena "tangkapan" tidak lagi berfungsi seperti biasanya, pengujian ini, meskipun benar-benar lulus, dilaporkan gagal.

Jadi saya kira saya tidak bisa melemparkan pernyataan NUnit yang tepat, atau menggunakan Assert.That dalam kode perpustakaan yang dimaksudkan untuk membantu pengembangan pengujian yang lebih cepat dengan melakukan tugas-tugas yang membosankan bagi pengguna?

Saya setuju dengan pernyataan sebelumnya bahwa jika pengecualian tidak dapat dikonsumsi oleh pengguna, itu tidak boleh tersedia untuk dibuang oleh pengguna; namun itu tidak menyelesaikan masalah di mana saya memiliki kode Assert.That untuk konsumen dan menguji untuk membuktikan bahwa mereka gagal karena kode melakukan apa yang seharusnya: gagal dengan pernyataan nunit.

Mungkin kita harus membuat beberapa API hasil?

@fluffynuts Jika saya memahami Anda dengan benar, klausa catch ada dalam kode pengujian Anda, bukan kode perpustakaan pengguna Anda. (Jika itu juga di perpustakaan pengguna, kita dapat membicarakannya, tetapi masalahnya sedikit berbeda.)

Tentu saja, NUnit memiliki pengujiannya sendiri, jadi kami memiliki potensi masalah yang persis sama ketika perubahan ini dilakukan. Secara alami, kami memodifikasi tes kami sendiri sehingga mereka terus lulus. Anda dapat melakukan hal yang sama.

Garis pertahanan pertama adalah Assert.Throws . Dalam kebanyakan kasus perilaku kegagalan pengujian, Anda dapat mengganti try / catch(AssertionException) dengan Assert.Throws<AssertionException> secara langsung. Secara internal Assert.Throws membuat TestExecutionContext sekali pakai terisolasi sehingga hasil pengujian Anda yang sebenarnya tidak tercemar oleh kesalahan yang Anda uji.

Dalam beberapa kasus, Anda mungkin perlu membuat konteks terisolasi Anda sendiri. Anda dapat melihat cara melakukannya dengan memeriksa kode untuk Assert.Throws .

Namun, sebagian besar pengujian kegagalan NUnit sendiri sebenarnya menggunakan pendekatan yang berbeda. Kami memiliki rakitan terpisah dengan pengujian yang dijalankan oleh program pengujian kami sendiri. Kami menangkap hasilnya dan kemudian dapat memeriksanya. Ini lebih banyak pekerjaan tetapi menghindari memasukkan terlalu banyak detail implementasi tentang NUnit ke dalam pengujian kami. Sebagian besar metode yang melakukan ini ditemukan di perakitan utilitas pengujian kami. Saya pikir itulah yang dimaksud @jnm2 .

Kirimkan pertanyaan apa pun yang Anda miliki atau hubungi saya secara offline untuk bantuan lebih lanjut terkait hal ini.

Terimakasih atas infonya. Ya, pernyataan ditangkap dalam kode pengujian. Assert.Throws biasanya akan melakukan trik, tetapi tes spesifik yang dimaksud menjalankan kode perpustakaan dengan delta "terlalu rendah" yang diizinkan untuk menguji nilai datetime yang harus dimasukkan ke dalam dan diambil dari database. Sebagian besar waktu, penyimpangan yang dialami untuk ini ke localdb adalah 1 ms, tetapi kadang-kadang melayang lebih tinggi - dan tes ini hanya bertujuan untuk menegaskan bahwa "kadang-kadang" terjadi. Jadi, saat ini, saya menjalankan kode dalam 4 utas paralel, 10 kali dan mengharapkan setidaknya satu kegagalan. Assert.Throws, sayangnya, terlalu deterministik untuk kasus ini, jadi saya harus berhenti menggunakan pengecualian nunit (atau Assert, di dalam kode perpustakaan), atau saya perlu mempelajari fu yang kalian gunakan. Saya menghargai petunjuk apa pun - dapat terjadi secara offline, jika Anda mau.

Heh, saya baru menyadari bahwa kegagalan tes pompa pesan untuk AsyncVoidVerificationScope saya yang telah saya lihat adalah masalah yang sama persis dengan yang dialami @fluffynuts . Sebenarnya karena pemutakhiran NUnit 3.10, bukan [perakitan: RestoreSynchronizationContext] saya ITestAction. Sangat membantu saya karena mengabaikan mereka saat melakukan banyak hal sekaligus. :D

Bagaimanapun, sepertinya yang ingin saya lakukan adalah membungkus permintaan delegasi saya dalam using (new TestExecutionContext.IsolatedContext()) seperti yang dilakukan Assert.Throws .

Assert.Throws dan Assert.ThrowsAsync tidak membuat konteks terisolasi sebelum memanggil delegasi async. Kenapa ini?

@fluffynuts Dulu, ketika saya pertama kali menulis Assert.Catch itu hanya menangkap pengecualian apa pun dan tidak menghasilkan kesalahan jika tidak ada pengecualian yang dilemparkan. Sayangnya, itu berubah dan kami tidak lagi memiliki padanan "netral" dari Assert.Throws . Anda bisa menulis satu, namun. Ini adalah versi yang belum diuji berdasarkan kode di Assert.Throws . Itu hanya menangani kode sinkron tetapi Anda dapat memperluasnya dengan mudah untuk async menggunakan kode tambahan dari Assert.Throws .

```C#
public static void Exception SafelyCatchAnNUnitException (kode TestDelegate)
{
Pengecualian catchException = null;

using (new TestExecutionContext.IsolatedContext())
{
    try
    {
        code();
    }
    catch (Exception ex)
    {
        caughtException = ex;
    }

    return caughtException;
}

}
```

Metode ini akan mengembalikan pengecualian apa pun yang dilemparkan, membersihkan sisa-sisa kesalahan yang ditinggalkan oleh metode penegasan NUnit. Jika tidak ada pengecualian yang dilemparkan, ia mengembalikan nol.

Dimungkinkan juga untuk menggunakan IsolatedContext() pada tingkat yang lebih tinggi dalam kode Anda untuk mengambil hasil pengujian yang sebenarnya dari kode tersebut. Itu akan memungkinkan Anda untuk menguji sepenuhnya pada tingkat hasil tes, tanpa referensi ke pengecualian. Saya telah memikirkan untuk menulis perpustakaan untuk jenis pengujian ini, yang menurut saya akan lebih unggul daripada cara NUnit saat ini melakukan pengujiannya sendiri.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat