Haruskah setiap metode mengembalikan nilai untuk Pengujian Unit?

12

Saya sedang belajar membuat tes Unit sederhana untuk akhirnya (dan mudah-mudahan) mulai melakukan hanya TDD; untuk saat ini saya mencoba menulis tes untuk kode yang sudah ditulis untuk melihat apa yang mungkin menyebabkan masalah. Ini salah satunya.

Katakanlah saya memiliki kelas sederhana ini (dengan Typescript-> Javascript):

class PrivateStuff {
    greeting: string;
    private _thisIsPrivate;

    constructor(isPrivate: boolean) {
        this._thisIsPrivate = isPrivate;
    }

    setPrivate(option) {
        this._thisIsPrivate = option;
        console.log("_thisIsPrivate changed to : " + option);
    }

    getPrivate() {
        console.log("_thisIsPrivate is : " + this._thisIsPrivate);
        return this._thisIsPrivate;        
    }
}

Dan saya menggunakannya dengan cara ini:

let privateStuff = new PrivateStuff(false);

let buttonSet = document.createElement('button');
buttonSet.textContent = "Set True";
buttonSet.onclick = function () {
    privateStuff.setPrivate(true);
}

let buttonGet = document.createElement('button');
buttonGet.textContent = "Get";
buttonGet.onclick = function() {
    console.log(privateStuff.getPrivate());
}
document.body.appendChild(buttonSet);
document.body.appendChild(buttonGet);

setPrivate()tidak perlu mengembalikan apa pun, tetapi karena itu saya tidak dapat mengujinya. Saat membuat unit test untuk itu, haruskah saya refactor kode?

Jika saya melakukan TDD, haruskah saya selalu membuat metode yang mengembalikan sesuatu hanya untuk dapat mengujinya? Atau saya melewatkan sesuatu?

PS Anda dapat melihat dan menjalankan kode di sini

distante
sumber
4
Jika Anda mengaturPrivate tidak akankah nilai getPrivate memberi tahu Anda jika itu berhasil?
JeffO
@ Jeff ya, saya melihat sekarang bahwa saya tidak hanya harus menggunakan kembali fungsi untuk memeriksa apakah itu berfungsi.
distante
"setPrivate () tidak perlu mengembalikan apa pun, tetapi karena itu saya tidak dapat mengujinya." Apakah itu menimbulkan efek yang dapat diamati? Jika demikian, Anda dapat mengujinya. Kalau tidak, tidak ada minat untuk mengujinya (dan tidak ada minat untuk menerapkannya).
mgoeminne
@mgoeminne Bagaimana jika metode ini batal dan menulis ke database / log atau mengirim pesan ke objek lain sebagai satu-satunya efeknya?
Andres F.
@AndresF. Anda dapat membaca dari database / log atau mengejek objek lain untuk mengonfirmasi bahwa data telah dikirim. Ini mungkin bukan tes "unit", tapi bukan itu yang sebenarnya penting.
Jacob Raihle

Jawaban:

21

Saya kira kesalahpahaman Anda di sini adalah bahwa "subjek yang diuji" harus selalu menjadi metode sendiri. Tapi itu tidak benar, meskipun beberapa metode dapat diuji tanpa menggunakan metode lain, ukuran khas dari SUT adalah kelas, atau beberapa metode dan fungsi yang berinteraksi dari satu kelas. Jadi, jika Anda memiliki metode yang mengubah keadaan internal suatu objek, harus selalu ada beberapa perubahan yang terlihat secara eksternal terhadap perilaku objek tersebut (jika tidak, tidak masuk akal untuk memiliki metode tersebut di tempat pertama). Dan dalam tes unit, Anda dapat memvalidasi perilaku ini secara tepat.

Sebagai contoh, katakanlah Anda memiliki kelas NumberFormatterdengan tanggung jawab untuk memformat angka floating point dengan cara yang telah ditentukan. Mari kita asumsikan itu berisi metode FormatToString(double d). Mari kita anggap lebih lanjut memiliki metode setDecimalSeparator, tetapi tidak getDecimalSeparator. Namun Anda dapat dengan mudah menulis tes jika setelah panggilan ke setDecimalSeparatormetode FormatToStringberperilaku dengan cara yang diinginkan. Tes seperti itu bisa terlihat seperti ini

  var nf = new NumberFormatter();
  nf.setDecimalSeparator(".");
  AssertEqual("12.34",nf.FormatToString(12.34))
  nf.setDecimalSeparator(",");
  AssertEqual("12,34",nf.FormatToString(12.34))

Jadi ini adalah tes yang berarti setDecimalSeparator, metode tanpa nilai balik.

Doc Brown
sumber
Saya mengerti, jadi dalam contoh saya yang tidak realistis saya dapat menggunakan fungsi rigetPrivate () ´ untuk melihat apakah ´_thisIsPrivate´ ini telah berubah dan berharap bahwa thatgetPrivate () ´ berfungsi tetapi dalam skenario kasus yang lebih nyata saya harus menguji objek yang sedang diubah . Terima kasih atas penjelasan Anda yang jelas!
distante