Unit Testing – Bagian III: Menyingkap yang tersembunyi
Sebelumnya, saya ingin sedikit merangkum apa yang telah kita bahas pada artikel Unit Testing - Bagian II. Kita sudah tau bagaimana cara membuat test project, lalu test class, dan test method. Kita juga sudah paham bagaimana mengeksekusi setiap test method, dan melakukan verifikasi di dalam masing-masing test method tersebut. Termasuk bagaimana melakukan verifikasi atas ekspektasi terhadap sebuah Exception. Yang tidak kalah pentingnya, kita pun sudah mengerti bagaimana cara melihat test outcome hingga ke code coverage nya. Dengan begitu, sudah ada sedikit pencerahan tentang gimana sih bentuknya unit testing itu. Mungkin sebelumnya ada yang bertanya-tanya seperti apa bentuknya unit testing itu. Sekarang.. setidaknya sudah sedikit terjawab "oo gitu toh yang namanya unit testing". Masih lupa-lupa ingat? Boleh dibaca lagi di sini.
Oia, please keep in mind bahwa pembahasan kita hingga tulisan ini cuman for the sake of getting the idea apa sih unit testing itu, kayak gimana sih bentuknya, implementasinya seperti apa sih (dengan menggunakan teknologi .NET). Belum sampai gimana cara menulis test dengan baik dan benar. Bahkan unit testing itu sendiri memiliki patterns yang sudah well acknowledged. Itu nanti ya, di tulisan-tulisan selanjutnya :) Dan contoh-contoh kode program yang saya tulis bukan contoh implementasi real world.
Yang tersembunyi
Seperti yang sudah kita ketahui bersama, untuk kepentingan security/information hiding, .NET memiliki modifier private, protected, dan internal. Tulisan ini akan membahas bagaimana melakukan unit test terhadap method/property dengan ketiga modifier tersebut.
Private methods
Ok, sekarang kita coba bahas tentang bagaimana melakukan unit test terhadap private methods. Terdapat perbedaan pendapat mengenai perlu atau tidaknya unit test dilakukan terhadap private methods. Perbedaan pendapat yang lebih mendasar bahkan perlu atau tidak implementasi sebuah private method di dalam software yang kita kembangkan. Tim Stall telah merangkum perbedaan tersebut di sini. Saya pribadi termasuk yang pro unit test terhadap private methods :). Dengan alasan prinsip unit testing, yaitu menguji semua bagian terkecil dari kode software yang kita kembangkan: unit. Dalam hal ini private methods juga unit seperti halnya public methods.
Teknik wrapping sebagai strategi
Strategi yang umum digunakan dalam menguji private methods adalah dengan menggunakan teknik wrapping. Teknik pembungkusan ini dalam banyak kasus (di luar konteks unit test terhadap private methods) telah terbukti ampuh.

Namun teknik wrapping dalam pengujian private methods memiliki banyak kekurangan seperti yang juga telah diulas oleh Tim Shall. Secara garis besar permasalahannya adalah kotornya production code kita. Akan banyak kode-kode tambahan entah itu wrapper class ataupun wrapper method yang hanya ditambahkan demi kepentingan unit testing saja. Tambahan kode pada test code tentu itu sebuah kebutuhan dalam unit testing, tapi tambahan kode pada production code for the sake of unit testing?? (Dengan teknologi yang ada saat ini,) it's a no-no menurut saya.
Mengulang apa yang telah disampaikan oleh Tim Shall, selain memenuhi kriteria a-trip (automatic, thorough, repeatable, independent, professional--dikutip dari buku Pragmatic unit testing in C# with Nunit, ditulis oleh Andy Hunt dan Dave Thomas), unit test pada private/protected methods juga harus memenuhi kriteria transparency, scope, dan simplicity. Transparency maksudnya jangan sampai karena unit test, menyebabkan bertambahnya kode pada production code. Scope berarti unit test tersebut harus bisa dijalankan pada debug mode dan release mode. Simplicity menggambarkan unit test yang kita buat membutuhkan minimal effort dengan resiko yang minimal pula dan mudah untuk dimodifikasi. Masih pada halaman web yang sama, Tim Shall memperlihatkan bahwa teknik-teknik wrapping tidak bisa memenuhi tiga kriteria tersebut secara keseluruhan.
Teknik reflection, generic type, dan extension method sebagai strategi
Dengan teknologi pemrograman saat ini, banyak sekali kita dapati magic di dalamnya. Reflection, generic type, dan extension method merupakan salah tiga magic yang ada di dalam teknologi .NET. Dengan reflection, kita bisa mengakses semua member yang dimiliki oleh sebuah object atau class walaupun modifier nya private sekalipun. Generic type memberikan generalisasi terhadap type yang kita gunakan tetapi tetap type-safe. Sementara itu, extension method memungkinkan kita untuk menyisipkan method tambahan terhadap sebuah object bertipe tertentu sesuai dengan kebutuhan.
Ok, langsung aja ke menu kita hari ini..
Pertama, kita tambahkan sebuah private method di class Fighter (saya masih menggunakan solution yang lalu) dengan nama PlaySoundEffect.
/// <summary>
/// Plays the sound effect.
/// </summary>
/// <param name="attackType">Type of the attack.</param>
/// <returns>The appropriate sound effect.</returns>
private string PlaySoundEffect(AttackType attackType)
{
switch( attackType )
{
case AttackType.SpecialKick:
return Properties.Resources.SpecialKickSound;
case AttackType.SpecialPunch:
return Properties.Resources.SpecialPunchSound;
case AttackType.Combo1:
return Properties.Resources.Combo1Sound;
case AttackType.Combo2:
return Properties.Resources.Combo2Sound;
default:
// An ordinary weak punch or kick.
return Properties.Resources.WeakAttackSound;
}
}
Sedikit catatan, saya juga memanfaatkan sebuah resources file bernama Resources di dalam folder Properties. Isinya adalah definisi resources yang kemudian saya gunakan pada kode di atas.

Selanjutnya saya membuat sebuah helper atau utility class yang saya namakan TypeAccessor. Dan saya tambahkan sebuah method bernama Invoke yang berfungsi untuk mengeksekusi method yang diinginkan dari sebuah instance object dengan teknik reflection.
namespace Fighting.Test
{
/// <summary>
/// This is a helper class to access the intended type's members.
/// </summary>
public static class TypeAccessor
{
private const BindingFlags bindingFlags =
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static;
public static object Invoke<InstanceType>(this InstanceType instance, string methodName, params object[] parameters) where InstanceType : class
{
// TODO: need to have some fancy validations.
return instance.GetType().GetMethod(methodName, bindingFlags).Invoke(instance, parameters);
}
}
}
Pada method Invoke di atas, proses yang terjadi adalah ambil type dari instance object melalui method GetType (yang akan menghasilkan type Type), lalu dapatkan method yang ingin dieksekusi melalui method GetMethod (yang akan menghasilkan type MethodInfo) dengan memberikan nama method sebagai parameter beserta binding flags nya, dan panggil method Invoke dengan memberikan instance object tersebut beserta parameter-parameter yang diperlukan oleh method yang ingin dieksekusi tersebut.
Sekarang kita siap melakukan unit test terhadap method PlaySoundEffect. Kita buka unit test kita, lalu tambahkan test method baru bernama PlaySoundEffectUsingTypeAccessorHelperTest.
/// <summary>
/// A test for PlaySoundEffect by using type accessor helper.
/// </summary>
[TestMethod]
public void PlaySoundEffectUsingTypeAccessorHelperTest()
{
Fighter target = new Fighter();
string expected = Fighting.Properties.Resources.Combo1Sound;
string actual = target.Invoke<Fighter>("PlaySoundEffect", AttackType.Combo1) as string;
Assert.AreEqual(expected, actual);
}
Sisanya, jalankan unit test, dan...

So sweet :)
Catatan kecil lagi, pada test method tersebut saya set nilai variable 'expected' dari Fighting.Properties.Resources.Combo1. Padahal modifier class Resources tersebut adalah internal yang artinya tidak bisa diakses oleh project lain termasuk project unit testing saya. Supaya class Resources bisa diakses dari project unit testing, saya menambahkan attribute InternalsVisibleTo di class AssemblyInfo pada project Fighting. Teknik ini juga yang akan kita gunakan dalam melakukan test terhadap internal method yang nanti akan saya bahas juga.
Kelemahan unit test terhadap private method dengan teknik reflection adalah casting type yang selalu terjadi setiap kali method Invoke dipanggil dari test yang kita miliki. Selain itu, nama method yang ingin dieksekusi pun harus di-supply dengan string nama method nya. Dan satu lagi, karena method yang inginkan dieksekusi secara dinamis (melalui reflection), semua parameter yang diberikan kepada method Invoke ini tidak dicek oleh compiler saat compile time.
Tapi, teknik ini lebih baik daripada teknik wrapping. Karena dengan teknik ini, tidak ada penambahan kode pada production code (memenuhi kriteria transparency), melingkupi mode debug maupun release (memenuhi kriteria scope), dan mudah menggunakannya--cukup dengan memanggil extension method Invoke melalui instance object dengan tipe apapun (memenuhi kriteria simplicity).
Teknik private accessor sebagai strategi
Visual Studio sudah menyediakan tool yang mudah bagi kita untuk melakukan unit test terhadap private method, yaitu private accessor. Private accessor adalah sebuah accessor class yang dibuat oleh Visual Studio. Accessor class ini berfungsi sebagai wrapper class yang bisa mengakses private members dengan menggunakan reflection.
Untuk membuat sebuah private accessor, cukup dengan klik kanan pada target class yang kita inginkan lalu pilih Create Private Accessor dan pilih project unit testing kita.

Lalu akan muncul private accessor baru di project unit testing kita di dalam folder Test References.

Atau, Visual Studio juga bisa membuatkan private accessor secara otomatis jika kita membuat unit test secara langsung untuk sebuah private method dengan cara yang pernah kita bahas sebelumnya.
Sekarang kita buat test method yang baru di test class kita. Dan akan ada sebuah type baru bernama Fighter_Accessor yang merupakan accessor class untuk class Fighter.
/// <summary>
/// A test for PlaySoundEffect by using private accessor.
/// </summary>
[TestMethod]
public void PlaySoundEffectUsingPrivateAccessorTest()
{
Fighter_Accessor target = new Fighter_Accessor();
string expected = Fighting.Properties.Resources.Combo1;
string actual = target.PlaySoundEffect(AttackType.Combo1);
Assert.AreEqual(expected, actual);
}
Dan kita jalankan unit test yang baru saja kita buat.

nice... :)
Jelas dengan private accessor kode unit testing kita jauh lebih rapih, kita nggak perlu bikin wrapper sendiri, nggak perlu bikin class untuk accessor helper, dan tidak perlu casting, semua private members dari sebuah object bisa kita akses layaknya akses terhadap public members. Tentunya dengan teknik ini ketiga kriteria transparency, scope, dan simplicity terpenuhi dengan baik.
Walaupun teknik ini terbilang jitu, namun ada kasus-kasus tertentu di mana penggunaan private accessor malah membuat masalah di kode kita. Saya akan memperlihatkan contoh-contoh kasusnya di artikel yang lain. Singkat cerita, tidak selamanya private accessor menjadi pilihan dalam menguji private method. Jika kita sedang dalam posisi ini, membuat accessor type helper menjadi teknik alternatif yang menjanjikan.
Protected methods
Untuk menguji sebuah method dengan modifier protected, teknik type accessor helper ataupun private accessor dari Visual Studio juga dapat digunakan sama halnya dengan menguji private method seperti yang sudah saya jelaskan di atas.
Namun ada satu teknik yang umum digunakan untuk melakukan unit test terhadap protected method. Caranya, pada project unit testing, kita tambahkan sebuah class helper yang merupakan turunan dari class yang memiliki protected method tersebut. Lalu buat sebuah wrapper method yang memanggil protected method tersebut.
Misalnya saya tambahkan sebuah protected method pada class Fighter:
/// <summary>
/// Determines whether the opponent is right in front.
/// </summary>
/// <returns>
/// <c>true</c> if the opponent is right in front; otherwise, <c>false</c>.
/// </returns>
protected bool IsOpponentRightInFront()
{
return _opponentDistance == 0;
}
Kemudian di test class (class FighterTest), saya tambahkan sebuah private class turunan dari class Fighter, dan didalamnya terdapat wrapper method untuk IsOpponentRightInFront dengan nama yang sama, hanya saja modifier nya public.
/// <summary>
/// The derrived class of Fighter for testing purpose.
/// </summary>
private class DerrivedFighter : Fighter
{
/// <summary>
/// A wrapper method for IsOpponentRightInFront.
/// </summary>
/// <returns>
/// <c>The parent's IsOpponentRightInFront value.</c>.
/// </returns>
public new bool IsOpponentRightInFront()
{
return base.IsOpponentRightInFront();
}
}
Perhatikan saya juga menambahkan modifier new pada wrapper method IsOpponentRightInFront. Tujuannya untuk menyembunyikan method IsOpponentRightInFront yang dimiliki oleh parent class yaitu class Fighter.
Sekarang, kita buat test method nya lalu eksekusi!
/// <summary>
/// A test for IsOpponentRightInFron.
/// </summary>
[TestMethod]
public void IsOpponentRightInFrontTest()
{
Fighter target = new DerrivedFighter() { OpponentDistance = 0 };
bool expected = true;
bool actual = (target as DerrivedFighter).IsOpponentRightInFront();
Assert.AreEqual(expected, actual);
}

It's green :)
Lalu, apakah teknik ini memenuhi kriteria transparency? Ya, tentu saja.. tidak ada penambahan kode sedikit pun pada production code. Memenuhi kriteria scope? Pastinya.. Teknik ini bisa melingkupi debug mode maupun release mode. Lalu, simplicity? Cukup dengan sekali saja membuat class turunan dan wrapper methods yang diperlukan, selanjutnya class ini bisa digunakan setiap kali dibutuhkan pada unit testing, dengan tetap mempertahankan OOP dan type safe.
Internal methods
Yang terakhir, kita akan coba melakukan unit test terhadap internal methods. Seperti halnya dengan private dan protected methods, kita bisa melakukan unit test terhadap internal methods dengan menggunakan teknik type accessor helper maupun teknik private accessor nya Visual Studio.
Tapi, ada satu teknik lagi yang bisa digunakan untuk bisa mengakses internal methods secara langsung dari project unit test. Sehingga kita tidak perlu menggunakan accessor helper bikinan sendiri ataupun private accessor Visual Studio. Dengan teknologi .NET saat ini, kita bisa menggunakan InternalsVisibleTo attribute untuk menandakan bahwa semua internal types dan internal members bisa terlihat (bisa diakses) oleh assembly yang kita tentukan (dalam hal ini, assembly yang kita inginkan adalah unit test project kita).
Saya menambahkan sebuah internal method bernama TauntOpponent pada class Fighter.
/// <summary>
/// Taunts the opponent.
/// </summary>
/// <returns>The taunt words.</returns>
internal string TauntOpponent()
{
return _opponentDistance <= CLOSE_DISTANCE_LIMIT ? Properties.Resources.CloseTaunt : Properties.Resources.FarTaunt;
}
Lalu, supaya method TauntOpponent ini bisa diakses oleh project unit test, kita perlu menambahkan InternalsVisibleTo attribute di AssemblyInfo project Fighting (project di mana target class kita yaitu class Fighter berada).
InternalsVisibleTo attribute bisa ditambahkan secara otomatis ketika kita membuat unit test untuk method TauntOpponent dengan cara klik kanan pada method tersebut lalu pilih create unit test. Akan muncul sebuah dialog box yang menanyakan apakah kita ingin menambahkan InternalsVisibleTo attribute pada project kita (file AssemblyInfo.cs) atau tidak. Jika kita memilih tidak, maka Visual Studio akan membuatkan private accessor sebagai alternatif. Selain dengan cara otomatis, tentunya kita juga bisa menambahkan InternalsVisibleTo attribute dengan cara manual.
[assembly: InternalsVisibleTo("Fighting.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100892c7870f2b465b9166c495024429e8dcfcc52224f793abef166e69b4e37b1d2c2f376a114ef8afd77a233188a7f4601d281060016c531599b8b05d46ae02114d12c3907623f596e692f65e2897cb60adc0d597df9176788d765516c60015d33d9d0362616d7e60c2d28bd85815c3d5d14761e822b42b4b712a16aa8be26e6c7")]
Perhatikan bahwa jika unit test assembly kita adalah strong named assembly (menggunakan strong name key), maka kita harus menyebutkan public key nya sebagai bagian dari parameter assembly name dari constructor InternalsVisibleTo seperti yang terlihat pada potongan kode di atas.
Berikutnya, kita buat unit test untuk method TauntOpponent.
/// <summary>
/// A test for TauntOpponent.
/// </summary>
[TestMethod]
public void TauntOpponentTest()
{
Fighter target = new Fighter() { OpponentDistance = 0 };
string expected = Fighting.Properties.Resources.CloseTaunt;
string actual = target.TauntOpponent();
Assert.AreEqual(expected, actual);
}
Lalu jalankan unit test tersebut.

Dan teknik ini pun memenuhi kriteria transparency, scope, dan simplicity.
Muncul pertanyaan, bukankah cukup dengan menggunakan private accessor saja, dengan begitu kita dapat menguji private methods sekaligus internal methods? mengapa perlu menggunakan InternalsVisibleTo attribute lagi jika private accessor saja sudah cukup? Seperti apa yang baru saja kita bahas di atas, penggunaan private accessor dalam kasus-kasus tertentu akan menimbulkan masalah yang lain. Lebih daripada itu, private accessor pada dasarnya adalah sebuah wrapper yang implementasi didalamnya menggunakan reflection. Tentunya 'cost' yang diperlukan dengan menggunakan private accessor lebih besar bila dibandingkan dengan menggunakan InternalsVisibleTo attribute yang hanya merupakan sebuah custom attribute. Untuk sebuah software development yang berskala besar, perbedaan penggunaan keduanya akan terasa signifikan. Jangan lupa juga, salah satu filosofi automated unit testing adalah harus bisa dilakukan dalam waktu yang relatif singkat. Selain itu, bisa jadi sebagian dari kita tidak suka dengan wrapper types yang dibuat oleh private accessor karena memiliki suffix "_Accessor" yang sedikit mengganggu mata.
Kesimpulannya, teknik apa yang terbaik untuk digunakan untuk melakukan unit test terhadap "yang tersembunyi", tergantung dari situasi dan kondisi kode yang akan kita test. Kita bisa pakai teknik yang mana saja selama memenuhi kriteria a-trip plus tiga kriteria tambahan yaitu transparency, scope, dan simplicity :)