Bagaimana cara memeriksa "tidak ada pengecualian" dalam pengujian unit MSTest saya?

89

Saya sedang menulis tes unit untuk satu metode ini yang mengembalikan "void". Saya ingin memiliki satu kasus yang lulus uji ketika tidak ada pengecualian yang dilemparkan. Bagaimana cara menulisnya di C #?

Assert.IsTrue(????)

(Dugaan saya adalah begini cara saya memeriksanya, tapi yang berbunyi "???")

Saya harap pertanyaan saya cukup jelas.

George yang penasaran
sumber
Apakah Anda menggunakan MSTest atau NUnit?
Matt Grande
2
Dalam MSTest pengecualian yang tidak tertangkap secara otomatis akan menyebabkan pengujian gagal. Apakah Anda mencoba memperhitungkan pengecualian yang tertangkap?
Phil
Anda dapat mencari "coba-tangkap untuk C #" dan itu akan menginstruksikan Anda tentang cara menangani pengecualian yang dilempar atau tidak dilempar.
Foggzie
1
Jika NUnit, lihat ke Assert.That (lambda). Throws.Nothing (Meskipun saya pikir itu berubah baru-baru ini)
Matt Grande

Jawaban:

139

Tes unit Anda akan tetap gagal jika pengecualian dilemparkan - Anda tidak perlu memasukkan pernyataan khusus.

Ini adalah salah satu dari sedikit skenario di mana Anda akan melihat pengujian unit tanpa pernyataan sama sekali - pengujian secara implisit akan gagal jika pengecualian dimunculkan.

Namun, jika Anda benar-benar ingin menulis pernyataan untuk ini - mungkin agar dapat menangkap pengecualian dan melaporkan "tidak mengharapkan pengecualian tetapi mendapatkan ini ...", Anda dapat melakukan ini:

[Test]
public void TestNoExceptionIsThrownByMethodUnderTest()
{
    var myObject = new MyObject();

    try
    {
        myObject.MethodUnderTest();
    }
    catch (Exception ex)
    {
        Assert.Fail("Expected no exception, but got: " + ex.Message);
    }
}

(di atas adalah contoh untuk NUnit, tetapi hal yang sama berlaku untuk MSTest)

Rob Levine
sumber
Jelas Anda tidak harus pergi dan menangkap pengecualian seperti itu untuk berlaku.
Pelayanan
7
Tes hanya akan gagal jika pengecualian yang tidak tertangkap muncul. Bergantung pada kode dalam penangan pengecualian, pengujian unit dapat lulus.
ediblecode
1
Ini berguna untuk Ms Unittest, jadi tidak ada metode Assert.DoesNotThrow (() di Unittest.
Başar Kaya
26

Di NUnit, Anda dapat menggunakan:

Assert.DoesNotThrow(<expression>); 

untuk menegaskan bahwa kode Anda tidak memunculkan pengecualian. Meskipun pengujian akan gagal jika pengecualian ditampilkan meskipun tidak ada Assert di sekitarnya, nilai dari pendekatan ini adalah Anda kemudian dapat membedakan antara ekspektasi yang tidak terpenuhi dan bug dalam pengujian Anda, dan Anda memiliki opsi untuk menambahkan pesan kustom yang akan ditampilkan dalam hasil tes Anda. Hasil pengujian yang dirancang dengan baik dapat membantu Anda menemukan kesalahan dalam kode yang menyebabkan pengujian gagal.

Menurut saya, menambahkan pengujian untuk memastikan bahwa kode Anda tidak memberikan pengecualian adalah valid; misalnya, bayangkan Anda memvalidasi input dan perlu mengubah string yang masuk menjadi string panjang. Mungkin ada kalanya string adalah null, dan ini dapat diterima, jadi Anda ingin memastikan bahwa konversi string tidak memunculkan pengecualian. Oleh karena itu akan ada kode untuk menangani kesempatan ini, dan jika Anda belum menulis tes untuk itu, Anda akan kehilangan liputan seputar bagian penting dari logika.

Clarkeye
sumber
1
DoesNotThrow eksplisit bagus. Jika Anda terbiasa melihat Assert. * Dalam pengujian, Anda mungkin mengira orang lain itu malas dan lupa.
Matt Beckman
Apakah ada padanannya di vstest atau mstest?
Dan Csharpster
1
@DanCsharpster, saya rasa tidak ada, setidaknya di MSTest - ketika saya membutuhkan fungsi ini di MSTest di masa lalu, saya telah melakukan sesuatu seperti ini: public class TestBase { //believe me, I don't like this anymore than you do. protected void AssertDoesNotThrow(Action action, string message) { try { action(); } catch (Exception) { Assert.Fail(message); } } }
Clarkeye
@ Clarkeye, itu ide yang menarik. Terima kasih! Mudah-mudahan, mereka akan belajar menyalin NUnit dengan lebih baik, di versi mendatang. Saya juga berpikir untuk menulis adaptor antara vstest dan NUnit.
Dan Csharpster
@DanCsharpster, satu hal yang mungkin ingin Anda lihat adalah pernyataan yang lancar, yang memiliki dukungan bagus untuk ShouldThrow dan ShouldNotThrow: github.com/dennisdoomen/fluentassertions/wiki#exceptions . Dokumen mengatakan itu kompatibel dengan MSTest (meskipun saya hanya menggunakannya dengan XUnit dan NUnit). Mungkin tidak melakukan semua yang Anda inginkan, tetapi Anda tetap dapat mencampurnya dengan pernyataan MSTest.
Clarkeye
12

Jangan menguji bahwa sesuatu tidak terjadi . Ini seperti memastikan bahwa kode tidak rusak . Itu semacam tersirat, kita semua berjuang untuk kode tanpa-kerusakan, tanpa bug. Anda ingin menulis tes untuk itu? Mengapa hanya satu metode? Tidakkah Anda ingin semua metode Anda diuji sehingga tidak ada pengecualian ? Setelah jalan itu, Anda akan mendapatkan satu pengujian ekstra, dummy, dan tanpa pernyataan untuk setiap metode dalam basis kode Anda. Itu tidak ada nilainya.

Tentu saja, jika persyaratan Anda adalah untuk memverifikasi bahwa metode tidak menangkap pengecualian , Anda menguji itu (atau membalikkannya sedikit; uji bahwa itu tidak membuang apa yang seharusnya ditangkap).

Namun, pendekatan / praktik umum tetap utuh - Anda tidak menulis pengujian untuk beberapa persyaratan buatan / samar yang berada di luar cakupan kode yang diuji (dan pengujian bahwa "berfungsi" atau "tidak melempar" biasanya merupakan contoh dari seperti - terutama dalam skenario ketika tanggung jawab metode diketahui dengan baik).

Sederhananya - fokuslah pada apa yang harus dilakukan kode Anda dan uji untuk itu.

km
sumber
10
-1 Saya dapat memikirkan fungsionalitas positif yang memerlukan dan pengecualian tidak dilempar. Untuk satu metode yang tugasnya menangani pengecualian, catat mereka dan ambil tindakan - tanpa membuang pengecualian lebih jauh. Anda membuat poin umum yang baik - tetapi kemudian berbicara secara absolut seolah-olah itu selalu benar.
Rob Levine
3
@RobLevine: Saya memahami contoh Anda dan menyadari Anda menulis tes dalam kasus seperti itu. Namun seperti yang Anda perhatikan, maksud saya memang tentang praktik yang lebih umum - bisa dikatakan, menguji apa yang seharusnya dilakukan kode Anda versus menguji apa yang tidak dilakukan kode Anda. Saya telah mengubah sedikit posting saya, sehingga maksud saya lebih jelas dan lebih dekat dengan apa yang ada dalam pikiran saya. Juga memberi Anda kesempatan untuk mempertimbangkan kembali suara Anda. Terima kasih atas klarifikasi dan maaf atas tanggapan yang tertunda.
km
4
suara negatif dihapus - saya tidak akan begitu senang dengan suara negatif di waktu berikutnya!
Rob Levine
4
Dalam proyek kami, kami memiliki kelas htmlvalidator, yang memunculkan pengecualian jika html tidak valid. Misalnya ketika pengguna memasukkan (menggunakan konsol) javascript dalam kombinasi kaya. Jadi dalam kode kasus saya apa yang kode saya lakukan adalah tidak membuang pengecualian (pendekatan daftar putih) dan saya perlu mengujinya.
Machet
1
Tidak setuju dengan jawaban ini. Menguji ketiadaan sesuatu terkadang dalam skenario tertentu bisa menjadi tes yang valid.
bytedev
7

Kelas pembantu ini membuat saya gatal dengan MSTest. Mungkin itu bisa menggores milikmu juga.

[TestMethod]
public void ScheduleItsIneligibilityJob_HasValid_CronSchedule()
{
    // Arrange
    var factory = new StdSchedulerFactory();
    IScheduler scheduler = factory.GetScheduler();

    // Assert
    AssertEx.NoExceptionThrown<FormatException>(() =>
        // Act
        _service.ScheduleJob(scheduler)
    );
}

public sealed class AssertEx
{
    public static void NoExceptionThrown<T>(Action a) where T:Exception
    {
        try
        {
            a();
        }
        catch (T)
        {
            Assert.Fail("Expected no {0} to be thrown", typeof(T).Name);
        }
    }
}
JJS
sumber
@Remco Beurskens - menambahkan tangkapan umum {} di akhir NoExceptionThrown <T> akan menekan kesalahan lain, yang bukan merupakan konsekuensi yang diinginkan dari metode ini. Ini bukan metode tujuan umum untuk menekan semua Pengecualian. Ini dimaksudkan untuk gagal hanya jika pengecualian dari tipe IS yang diketahui dilemparkan.
JJS
1
Ini sangat tua sekarang, tetapi Assertmemiliki pengakses properti tunggal, Thatyang dapat digunakan sebagai pengait untuk metode ekstensi. Mungkin lebih rapi, dan lebih mudah ditemukan, Assert.That.DoesNotThrow()daripada memilikinya AssertEx.DoesNotThrow(). Ini hanya opini.
Richard Hauer
3

Saya suka melihat Assert.Whateverdi akhir setiap tes, hanya untuk konsistensi ... tanpa tes, apakah saya benar-benar yakin tidak seharusnya ada tes di sana?

Bagi saya, ini sesederhana meletakkan Assert.IsTrue(true);

Saya tahu saya tidak sengaja memasukkan kode itu ke sana, dan karena itu saya harus cukup percaya diri dengan membaca sekilas bahwa ini seperti yang dimaksudkan.

    [TestMethod]
    public void ProjectRejectsGappedVersioningByDefault() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        Assert.Throws<ScriptProject.InvalidProjectFormatException>(() => {
            var sut = new ScriptProject(files);
        });

    }

    [TestMethod]
    public void ProjectAcceptsGappedVersionsExplicitly() {

        var files = new List<ScriptFile>();
        files.Add(ScriptProjectTestMocks.GetVersion1to2());
        files.Add(ScriptProjectTestMocks.GetVersion3to4());

        var sut = new ScriptProject(files, true);

        Assert.IsTrue(true);   // Assert.Pass() would be nicer... build it in if you like

    }
jleach
sumber
Ini tidak sama. Jika kode Anda muncul, tidak ada pernyataan yang akan dipukul dan pengujian Anda akan gagal. Anda ingin terhubung ke framework pengujian dengan menyatakan sebuah kondisi.
DvS
1

Teman saya, Tim, memberi tahu saya tentang ExpectedException . Saya sangat suka b / c ini karena lebih ringkas, lebih sedikit kode, dan sangat eksplisit bahwa Anda menguji pengecualian.

[TestMethod()]
[ExpectedException(typeof(System.Exception))]
public void DivideTest()
{
    int numerator = 4;
    int denominator = 0;
    int actual = numerator / denominator;
}

Anda dapat membaca lebih lanjut tentang itu di sini: Penggunaan Atribut ExpectedException .

Jess
sumber
2
OP tidak meminta pengecualian.
Daniel A. White
Saya akan meninggalkan jawaban ini di sini. Saya menemukan pertanyaan ini saat mencari google untuk bagaimana menguji pengecualian dan jawaban ini saya pikir perlu ada di sini. OP telah menjawab pertanyaan mereka 7 tahun yang lalu. Bahkan tautan ke jawaban lain menurut saya bermanfaat.
Jess
Baik, Tim. 🤔
ruffin