JavaScript testlerinizi otomatize etmeye başladığınızda birçok soruyla karşılaşırsınız. Yüksek ihtimalle de Birim Test, Test Odaklı Geliştirme(Test-Driven Development) ve Davranış Odaklı Geliştirme(Behavior-Driven Development) hakkında konuşan insanlar göreceksiniz. Peki ya bunlardan hangisi en iyi yaklaşım? Hepsini de kullanabilir miyiz?
Birçok JavaScript geliştiricisiyle bu konuyu konuştum ve aslında bu sorunun cevabı hakkında biraz kafa karışıklığı olduğunu gözlemledim. Şimdi gelin birlikte Birim Test, TOG ve DOG nedir, ne değildir hep beraber bakalım ve bu konular hakkındaki bazı yanlış anlaşılmaları düzeltelim. 🙂
Birim Test (Unit Testing)
Birim Test yalnızca tek bir birim kod parçasına odaklanır; genellikle tek bir fonksiyona ya da modüle, bu bazen bir satır bazen de on bin satır kod olabilir. Testi tek bir fonksiyona özgü yapmak, onu daha basit, kolay yazılır ve daha hızlı koşulur kılar. Bu, birçok Birim Test’e sahip olabileceğiniz anlamına geliyor ki bu da daha fazla hata yakalamak demek. Bu testler kodunuzda bazı değişiklikler yapmak istediğinizde gerçekten çok işe yarıyorlar. Örneğin kodunuzun çalıştığını doğrulamak için elinizde bir dizi Birim Test olduğunu düşünelim; fakat kodda bir yeri değiştirmeniz gerekiyor, Birim Testler sayesinde kodunuzu güvenle değiştirebilirsiniz ve kodunuzun diğer kısımlarının doğru çalıştığından emin olabilirsiniz.
Birim Testi, ağ erişimi ve veri tabanı erişimi gibi bağımlılıklardan izole edilmelidir. Bu tarz bağımlılıkları taklitle(fake) kontrol edebileceğiniz araçlar mevcut. Bu, bütün senaryoların test edilmesi işini kolaylaştırır, aksi takdirde çok fazla kurulum yapmanızı gerekir. Örneğin sadece bir test koşmak için tüm veri tabanını kurmak zorunda olduğunuzu düşünün. “Yok sağ ol” dediğinizi duyar gibiyim. 🙂
Birim Test’in yazılabilmesi için belirli bir sentaks olduğuna dair yanlış bir kanı var. Sözde adı “xUnit sytle” olan bu söz dizimi biraz eski test araçlarında yaygın. Aşağıda “xUnit style” kullanılan bir Mocha örneği yer alıyor:
suite('My test suite name', function() {
setup(function() {
//do setup before tests
});
teardown(function() {
//clean up after tests
});
test('x should do y', function() {
//test something
});
});
Ancak bu sadece aracın nasıl göründüğüne dair bir örnek. Herhangi bir araç kullanmak zorunda değilsiniz; hatta düz JavaScript’le bile Birim Test’ler yazabilirsiniz.
//suite: User
//test: Name should start empty
var user = new User();
if(user.getName() !== '') {
throw new Error('User name should start as empty');
}
//test: Password should be hashed
var user = new user();
user.setPassword('hello');
if(user.getPassword() != bcrypt('hello')) {
throw new Error('User password should be hashed with bcrypt');
}
Birim Test’in temel parçaları: Testler, yalnızca bir şeyi test eder ve hepsi birbirinden izole edilmiştir. Böyle Script’leri ilkel Birim Test’leri yazmak için kullanabilirsiniz. Fakat Mocha ya da Jasmine gibi gerçek bir Birim Testi aracı kullanmak test yazmayı tabii ki kolaylaştıracaktır. Bunun yanında test başarısız olduğunda rapor etme gibi diğer güzel özelliklerinden de faydalanabilirsiniz.
Bazıları herhangi otomatize edilmiş bir testin Birim Test olduğunu düşünüyor; fakat bu doğru değil. Birçok farklı türde otomatize test var ve hepsinin de kendine ait farklı amaçları var.
Aşağıda en yaygın 3 tür otomatize test yer alıyor:
- Birim Testi: Yalnızca tek bir fonksiyon ya da objenin test edildiği ve bütün parçaların birbirinden izole olduğu bir test.
- Entegrasyon Testi: Birden çok parçanın birlikte test edildiği bir test. Örneğin, veri tabanı erişim kodunu bir test veri tabanına karşı test etmek.
- Kabul Testi (İşlevsellik Testi): Tüm uygulamayı otomatize test etme. Örneğin, Selenium gibi bir araç kullanarak tarayıcıyı otomatize ederek çalıştırmak.
Eğer Birim Testi yazarken zorlanıyorsanız, büyük ihtimalle yazdığınız bir Birim Testi değildir. Entegrasyon ve Kabul Testleri daha karmaşık ve genellikle daha yavaş koşulur. Ayrıca bakımları Birim Test’e göre daha zordur. Özetle eğer probleminiz olursa doğru türde test yazdığınızdan emin olun.
Test Odaklı Geliştirme (TDD)
TDD ya da Test-Odaklı Geliştirme test yazma ve testleri koşma sürecidir. Bunu takiben çok yüksek bir test coverage’a sahip olunmasını mümkün kılar. Test coverage dediğimiz şey otomatize test edilen kodun yüzdesine verilen isimdir. Yani yüksek bir test kapsamına sahip olmak iyi diyebiliriz. Ayrıca TOG testlerinizde benzer hataların bulunma olasılığını azaltır, aksi takdirde izlenmesi zor olabilir.
TOG süreci aşağıdaki adımlardan oluşmaktadır:
- Test yazarak başlayın.
- Testi ve herhangi diğer testleri koşun. Bu noktada yeni eklediğiniz test başarısız olmalıdır. Eğer burada başarısız olmadıysa doğru şeyi test etmiyor olabilir ve içerisinde hata barındırıyor olabilir.
- Testi geçebilecek minimum miktarda kod yazın.
- Yeni testin başarılı olup olmadığını kontrol etmek için testleri tekrar koşun.
- İsteğe bağlı olarak kodunuzu yeniden yazın.
- 1. Adımdan tekrar edin.
Öğrenmek için elbette biraz çaba harcamanız gerekiyor; ancak zaman harcadıktan sonra size geri dönüşü büyük olacaktır. TOG projelerinde code-coverage(kod kapsamı) oranı %90 – %100 arasında değişmektedir, yani kodun bakımı ve yeni özelliklerin kazandırılması oldukça kolaydır. Çok sayıda testiniz olması sebebiyle başka bir yeri de bozmadan, kodunuza ve yaptığınız değişikliklere güvenebilirsiniz. Bazıları TOG için “xUnit style” test aracını kullanmamız gerektiğini düşünüyor. Fakat doğrusu şöyle ki TOG, Birim Test’lerle harikulade çalışır ancak tabii ki diğer test yöntemlerine de uygulanabilir. Spesifik bir araç ya da sentaks gerektirmez.
Pek çok geliştirici için TOG ile ilgili en zor şey kod yazmadan önce testleri yazmak zorunda olmalarıdır.
Davranış Odaklı Geliştirme (BDD)
BDD ya da Davranış Odaklı Geliştirme muhtemelen en büyük karışıklık kaynağıdır. Otomatize testlere uygulandığında DOG harika testler yazmak için en iyi uygulamalar kümesidir. DOG, TOG ve Birim Test yaklaşımlarıyla birlikte kullanılabilir ve kullanılmalıdır.
DOG’nin çözümlediği en önemli şeylerden biri Birim Testlere uygulanmasındaki detaylardır. Kötü birim testlerindeki ortak problem test edilen fonksiyonun nasıl geliştirildiğine çok fazla bel bağlamalarıdır. Yani, fonksiyonunuzu güncellerseniz(input ve output’ları değiştirmeden güncelleseniz bile) testi de güncellemeniz gerekir. Bu bir problemdir; çünkü değişiklikleri zorlaştırır.
Davranış Odaklı Geliştirme nasıl test etmemiz gerektiğini bize gösterir. Uygulamayı test etmek yerine davranışı test etmemizi öğütler.
Gelin şimdi hep beraber Uygulama Odaklı ve Davranış Odaklı bir örnek inceleyelim.
suite('Counter', function() {
test('tick increases count to 1', function() {
var counter = new Counter();
counter.tick();
assert.equal(counter.count, 1);
});
});
Bu, hayali bir “counter” nesnesinin birim testi. “tick()” metodu çağrıldıktan sonra değerin “1” olmasını test ettik. Fakat testte bir problem var. Test “counter” ın 0’dan başlayacağı gerçeğine bağlı. Diğer bir deyişle bu test iki şeye dayanıyor:
- “Counter” 0’dan başlıyor.
- “tick()” birer birer artıyor.
Aslında “counter” ın 0’dan başlaması tick() metodunun davranışıyla ilgili olmayan bir uygulama detayı. Bu nedenle test üzerinde herhangi bir etkisi olmamalıdır. Testi böyle yazmış olmamızın tek sebebi davranış-odaklı değil de uygulama-odaklı düşünmüş olmamızdır.
BDD (Davranış Odaklı Geliştirme) davranışları test etmeyi önerir; bu nedenle kodun nasıl uygulandığını düşünmek yerine senaryonun ne olduğunu düşünmeye zaman harcıyoruz. Genellikle BDD testlerini “Bir şeyler yapmalı” şeklinde ifade edersiniz. Yani “counter” un bir “tik” yaptığında “count” un bir sayı artırılması gerekir.
Buradaki önemli kısım uygulamadan ziyade senaryoyu düşünmek; böylelikle daha iyi bir test tasarlayabilirsiniz.
describe('Counter', function() {
it('should increase count by 1 after calling tick', function() {
var counter = new Counter();
var expectedCount = counter.count + 1;
counter.tick();
assert.equal(counter.count, expectedCount);
});
});
Mocha’nın DOG stili fonksiyonlarını kullanan bu testte uygulama detayını kaldırdık. “counter”ın 0’dan başlamasına güvenmek yerine davranışı test etmek açısından daha mantıklı olan “counter.count + 1” ile karşılaştırıyoruz.
Bazen ihtiyaçlarınız değişir. Farz edelim ki, bir nedenden ötürü “counter”ın 0’dan farklı bir değerden başlaması gerekiyor. Eskiden olsa bunun için testi değiştirmek gerekirdi; ancak DOG varyantı ile bunu yapmaya gerek yok.
Sonuç
Birim Testi → “NE?”,
TDD(Test Odaklı Geliştirme) → “NE ZAMAN?”,
BDD(Davranış Odaklı Geliştirme) → “NASIL?” sorularını yanıtlamaktadır.
Her birini ayrı ayrı kullanabileceğiniz gibi, en iyi sonuçları elde etmek için birbirlerini çok iyi tamamladıklarından dolayı birleştirip kullanmanızı tavsiye ederim.
Kaynak: https://codeutopia.net/blog/2015/03/01/unit-testing-tdd-and-bdd/
Çeviren: Ayşenur Yılmaz