Bu soruya kısa bir giriş. Şimdi TDD'yi ve son zamanlarda BDD'yi bir yıldan fazla bir süredir kullanıyorum. Testlerimi daha verimli yazmak için alay etme gibi teknikleri kullanıyorum. Son zamanlarda kendime küçük bir para yönetimi programı yazmak için kişisel bir projeye başladım. Eski kodum olmadığından TDD ile başlamak için mükemmel bir projeydi. Talihsiz TDD'nin sevincini o kadar fazla yaşamadım. Hatta projemden vazgeçtim ki eğlencemi o kadar mahvediyordum.
Problem neydi? Testlerin / gereksinimlerin programın tasarımını geliştirmesine izin vermek için TDD benzeri bir yaklaşım kullandım. Sorun yazma / refactor testleri için geliştirme süresinin yarısından fazlasının olmasıdır. Sonuçta daha fazla özellik uygulamak istemedim çünkü yeniden test edip birçok teste yazmak zorunda kalacağım.
İşte bir sürü eski kodum var. Burada daha fazla entegrasyon ve kabul testi ve daha az birim testi yazarım. Bu kötü bir yaklaşım gibi görünmüyor çünkü böcekler çoğunlukla kabul ve entegrasyon testleri tarafından tespit ediliyor.
Benim fikrim, sonuçta birim testlerden daha fazla entegrasyon ve kabul testi yazabilmemdi. Hataları tespit etmek için dediğim gibi, birim testleri entegrasyon / kabul testlerinden daha iyi değildir. Birim testi de tasarım için iyidir. Bunları çok yazdığımdan beri sınıflarım her zaman iyi bir test edilebilir olacak şekilde tasarlandı. Ek olarak, testlerin / gereksinimlerin tasarıma yol göstermesine izin verme yaklaşımı çoğu durumda daha iyi bir tasarıma götürür. Birim testlerinin son avantajı, daha hızlı olmalarıdır. Neredeyse ünite testleri kadar hızlı olabileceklerini bilmek için yeterince entegrasyon testi yazdım.
Ben öğrendim web üzerinden bakıyordu sonra söz konusu madende çok benzer fikirler olduğunu burada ve orada . Bu fikir hakkında ne düşünüyorsunuz?
Düzenle
Tasarımın iyi olduğu yerlere bir örnek sorulara cevap vermekle birlikte, bir sonraki gereksinim için çok büyük bir yeniden düzenlemeye ihtiyacım vardı:
İlk başta belirli komutları yerine getirmek için bazı gereksinimler vardı. Genişletilebilir bir komut ayrıştırıcı yazdım - bir tür komut isteminden komutları ayrıştırıp modelde doğru olanı çağırdım. Sonuç, bir görünüm modeli sınıfında temsil edildi:
Burada yanlış bir şey yoktu. Tüm sınıflar birbirinden bağımsızdı ve kolayca yeni komutlar ekleyebilir, yeni veriler gösterebilirdim.
Bir sonraki şart, her komutun kendi görünüm temsiline sahip olması gerektiği idi - komutun sonucunun bir tür önizlemesi. Yeni gereksinime göre daha iyi bir tasarım elde etmek için programı yeniden tasarladım:
Bu da iyiydi, çünkü şimdi her komutun kendi görüş modeli ve dolayısıyla kendi ön izlemesi var.
Mesele şu ki, komut ayrıştırıcısının komutları belirteç tabanlı bir ayrıştırma kullanmak üzere değiştirildiği ve komutları yürütme yeteneğinden sıyrıldığı. Her komut kendi görünüm modeline sahipti ve veri görünüm modeli sadece mevcut olan komut görünüm modelini sadece gösterilmesi gereken verileri bildiğinden biliyor.
Bu noktada bilmek istediğim, yeni tasarımın mevcut herhangi bir şartı ihlal etmemesiydi. Kabul testimden HERHANGİ bir tane değiştirmek zorunda değildim. Çok büyük bir iş yığını olan neredeyse HER ünite testini yeniden düzenlemek ya da silmek zorunda kaldım.
Burada göstermek istediğim şey geliştirme sırasında sıkça görülen ortak bir durum. Eski ya da yeni tasarımlarla ilgili herhangi bir sorun yoktu, sadece doğal olarak gereksinimlerle değişti - nasıl anladım, bu TDD'nin tasarımın geliştiği bir avantajı.
Sonuç
Tüm cevaplar ve tartışmalar için teşekkürler. Bu tartışmanın özeti olarak bir sonraki projem ile test edeceğim bir yaklaşım düşündüm.
- Öncelikle her zaman yaptığım gibi bir şey uygulamadan önce tüm testleri yazıyorum.
- Gereksinimler için ilk önce tüm programı test eden bazı kabul testleri yazarım. Sonra gereksinimi uygulamam gereken bileşenler için bazı bütünleştirme testleri yazarım. Bu gerekliliği yerine getirmek için başka bir bileşenle birlikte çalışan bir bileşen varsa, her iki bileşenin birlikte test edildiği bazı entegrasyon testlerini de yazarım. Son fakat en az değil, eğer bir algoritma ya da yüksek permütasyona sahip başka bir sınıf yazmak zorunda kalırsam - örneğin bir seri hale getirici - bu belirli sınıflar için birim testleri yazarım. Diğer tüm sınıflar test edilmez, ünite testleri yapılır.
- Hatalar için işlem basitleştirilebilir. Normalde bir hataya bir veya iki bileşen neden olur. Bu durumda, hatayı test eden bileşenler için bir entegrasyon testi yazardım. Bir algoritmayla ilgili olsaydı, sadece bir birim testi yazardım. Eğer hatanın oluştuğu bileşeni tespit etmek kolay değilse, hatayı bulmak için bir kabul testi yazardım - bu bir istisna olmalı.