Unit tests and DRY

One of common things that I unit test with NUnit is testing throwing or not throwing a specific exception. This is done using Assert.Throws and Assert.DoesNotThrow. I used to write 2 method for a exception assert unit test. One that do the actual work and one for unit test previous method. Consider following:

pubic void method1()
{
int a =1;
int b=2;
//plenty setup needed here

MyClass.DoSomething(a, b);
}

[Test]
public void DoSomethingTest()
{
Assert.DoesNotThrow(method1);
}

Now suppose that you have to unit test MyClass.DoSomething against many similar inputs. One way to do is repeat method1 and DoSomethingTest as needed. A disadvantage is that it’s against DRY principle. As Assert.DoesNotThrow ony accepts methods that has not parameter, I couldn’t stop to repeat initialization/setup codes in every method.

Fortunately today I found that I can use Anonymous Methods with Assert.Throws and Assert.DoesNotThrow without need to create several methods. Using this way DRY is leveraged in unit tests. See following example:

[Test]
public void DoSomethingTest()
{
int a1 = 1;
int b1 =2;

int b2 =4;

int b3 = -1;

Assert.DoesNotThrows(delegate()
{
MyClass.DoSomething(a1, b1);
});

Assert.DoesNotThrows(delegate()
{
MyClass.DoSomething(a1, b2);
});

Assert.DoesNotThrows(delegate()
{
MyClass.DoSomething(a1, b3);
});

Note: Many others have problems with applying DRY or KISS with unit tests including this one.

‫چطور یک attribute ناقابل ده روز سرکارم گذاشت!

چند وقت پیش یک پروژه تستی کوچک NHibernateی ایجاد کردم برای ذخیره و بازیابی چند کلاس ساده. یک پروژه تست هم با استفاده NUnit درست کردم برای تست آن. در تست کردن به یک خطای آزار دهنده برخورد کرده بودم. طبق معمول از سر بی‌دقتی فقط آخر پیغام خطا را می‌خواندم که گفته بود don’t flush the Session after an exception occurs. به همین خاطر به شدت به مدیریت session مربوط به NHibernate در متودهای [SetUp] و [TearDown] مشکوک شده بودم. خیلی آن را بالا و پایین کردم و کلی آن را با نمونه کدهای قبلی مقایسه کردم. آخرش متقاعد شدم یا ایراد از همان دو متود Setup و TearDown است یا به این خاطر است که این بار از روش جدیدی برای ایجاد پروژه‌ی اصلی استفاده کرده بودم.

 توی این هیری ویری هم هاردم سوخت و پروژه یک هفته خوابید. تا این که امشب بعد از کلی دقت به پیغام خطا فهمیدم که پیغام خطا با not-null property references a null or transient شروع می‌شود. البته جستجوی این خطا هم در اینترنت باز هم بیشتر مرا گمراه کرد. نمی‌دانم در «یک لحظه» چه اتفاقی افتاد که به mapping کلاس مربوطه شک کردم و نگاهی به آن انداختم. حدستان درست است، علت خطا در mapping نهفته بود. در تعریف همه propertyها یک attribute وجود داشت به اسم not-null که برابر true قرار داده شده بود. در واقع چیزی که برای من اتفاق افتاده بود خطا نبود. بلکه خود من از طریق آن attribute به NHibernate گفته بودم که آن property حق ندارد null باشد و NHibernate هم فقط داشت این موضوع را به من یادآوری می‌کرد چون من در بعضی جاهای تستم مقدار بعضی propertyها را اصلاً set نمی‌کردم.

این بود علت خطایی که ده روز کامل من را سر کار گذاشته بود و اعتماد به نفسم را از بین برده بود. البته دنیای برنامه‌نویسی و به طور کلی دنیای کامپیوتر پر از این مشکلات است که اولش فکر می‌کنیم چه خطای عجیب و غریب و پیچیده‌ای است و آخرش می‌فهمیم علت آن یک موضوع کاملاً پیش پا افتاده است. من فقط دوست دارم بدانم چطور می‌شود وقوع آن «یک لحظه‌های» طلایی را جلوتر انداخت. نظر شما چیست؟