TDD'de yapılan ilk testte ihtiyacınız olacağını düşündüğünüz nesneleri yaratıyor


15

TDD için oldukça yeniyim ve herhangi bir uygulama kodundan önce geldiğinde ilk testimi oluştururken sorun yaşıyorum. Uygulama kodunun herhangi bir çerçevesi olmadan, istediğim ilk testi yazmakta özgürüm, ancak her zaman sorun hakkında Java / OO düşünce tarzım tarafından lekelenmiş gibi görünüyor.

Örneğin benim Github ConwaysGameOfLifeExample benim yazdım ilk test (rule1_zeroNeighbours) Henüz uygulanmamış bir GameOfLife nesnesi oluşturarak başladı; var olmayan bir set yöntemi, var olmayan bir adım yöntemi, var olmayan bir get yöntemi olarak adlandırılır ve sonra bir iddia kullanılır.

Daha fazla test yazıp yeniden düzenlediğimde testler gelişti, ama aslında böyle bir şeye benziyordu:

@Test
public void rule1_zeroNeighbours()
{
    GameOfLife gameOfLife = new GameOfLife();
    gameOfLife.set(1, 1, true);
    gameOfLife.step();
    assertEquals(false, gameOfLife.get(1, 1));
}

Uygulamanın tasarımını bu ilk aşamada bu ilk testi yazmaya nasıl karar verdiğime dayanarak zorladım.

TDD'yi anladığınız şekilde bu iyi mi? Testlerimin ve uygulamamın zaman içinde yeniden düzenleme ile geliştiği için TDD / XP prensiplerini takip ediyor gibi görünüyorum ve bu nedenle bu ilk tasarım işe yaramazsa, değişime açık olurdu, ancak çözüm bu şekilde başlatarak.

İnsanlar TDD'yi başka nasıl kullanıyor? Hiçbir GameOfLife nesnesi, sadece ilkel ve statik yöntemler ile başlayarak daha fazla yeniden düzenleme yineleme olabilirdi ama bu çok tutarlı görünüyor.


5
TDD, ne dikkatli planlama ne de dikkatli tasarım deseni seçiminin yerini almaktadır. Bununla birlikte, testin ilk birkaç satırını karşılamak için herhangi bir uygulama yazmadan önce, planınızın aptal olduğunu, yanlış kalıbı seçtiğinizi veya hatta sadece bir sınıfı testinizin istediği şekilde çağırmanın garip veya kafa karıştırıcı olduğunu unutmayın.
svidgen

Yanıtlar:


9

Uygulamanın tasarımını bu ilk aşamada bu ilk testi yazmaya nasıl karar verdiğime dayanarak zorladım.

Bence sorunuzun kilit noktası budur, bunun istenip istenmediği, ön tarafın tasarımını yapmanız ve ardından uygulamayı doldurmak için TDD'yi kullanmanız gerektiği fikrine ya da durron'un testlerin dahil edilmesi gerektiği fikrine dayanıp dayanmamanıza bağlıdır. hem tasarımı hem de uygulamayı hayata geçiriyor.

Bunlardan hangisini tercih ettiğinizi (veya ortada nereye düştüğünüzü) tercih olarak kendiniz için keşfetmeniz gereken bir şey olduğunu düşünüyorum. Her yaklaşımın artılarını ve eksilerini anlamak yararlıdır. Muhtemelen çok şey var, ama ana olanlar:

Pro Ön Tasarım

  • TDD tasarım konusunda iyi bir süreç olsa da, mükemmel değil. Somut bir hedef göz önünde bulundurulmadan TD yapmak bazen çıkmaz sokaklarda koşabilir ve en azından bu çıkmaz sokaklardan en azından bir kısmı, nereye gitmek istediğinize dair biraz açık düşünmeyle önlenebilirdi. Bu blog makalesi , bu argümanı Romen Rakamları kata örneğini kullanarak yapar ve bunu göstermek için oldukça güzel bir son uygulamaya sahiptir.

Profesyonel Test Sürüş Tasarımı

  • Uygulamanızı kodunuzun bir istemcisi (testleriniz) etrafında oluşturarak, gereksiz test senaryoları yazmaya başlamadığınız sürece YAGNI-aderansına hemen hemen ücretsiz olarak sahip olursunuz. Daha genel olarak, bir tüketici tarafından kullanımı etrafında tasarlanan bir API alırsınız, sonuçta istediğiniz şey budur.

  • Herhangi bir kod yazmadan önce sadece boşlukları doldurmadan önce bir grup UML diyagramı çizme fikri güzel, ancak nadiren gerçekçi. Steve McConnell'in Code Complete'te, tasarım ünlü olarak "kötü bir sorun" olarak tanımlanır - en azından kısmen çözmeden tam olarak anlayamadığınız bir sorun. Bunu, altta yatan sorunun kendisinin değişen gereksinimlerle değişebileceği gerçeğiyle birleştirin ve bu tasarım modeli biraz umutsuz hissetmeye başlar. Test sürüşü, sadece uygulamada değil, aynı zamanda bir tasarımda sadece bir iş parçasını ısırmanıza izin verir ve en azından kırmızıdan yeşile dönme ömrü boyunca bu görevin güncel ve ilgili olacağını bilir.

Özel örneğinize gelince, durron'un dediği gibi, en basit testi yazarak, tasarımın dışına çıkarak, yapabileceği minimum arayüzü tüketerek bir yaklaşımla devam ettiyseniz, muhtemelen kod snippet'inizdekinden daha basit bir arayüzle başlarsınız .


Bağlantı Ben okumak çok güzeldi. Bunu paylaştığın için teşekkürler.
RubberDuck

1
@ RubberDuck Bir şey değil! Aslında buna tamamen katılmıyorum, ama bence bu bakış açısını savunmak için mükemmel bir iş çıkarıyor.
Ben Aaronson

1
İkisini de yaptığımdan emin değilim, ama durumunu iyi yapıyor. Bence doğru cevap ortada bir yerde. Bir planınız olmalı, ama kesinlikle testleriniz garip geliyorsa, yeniden tasarlayın. Neyse ... ++ iyi eski fasulye göstermek.
RubberDuck

17

Testi ilk etapta yazmak için , daha sonra uygulayacağınız API'yi tasarlamanız gerekir . Tüm GameOfLife nesneyi oluşturmak için testinizi yazıp testinizi uygulamak için bunu kullanarak yanlış ayağa zaten başladınız .

JUnit ve Mockito ile Pratik Birim Testinden :

İlk başta orada olmayan bir şeyi yazmak için garip hissedebilirsiniz. Kodlama alışkanlıklarınızda küçük bir değişiklik gerektirir, ancak bir süre sonra bunun harika bir tasarım fırsatı olduğunu göreceksiniz. Önce testler yazarak, bir müşterinin kullanması için uygun bir API oluşturma şansınız vardır. Testiniz yeni doğan bir API'nın ilk müşterisidir. TDD'nin asıl amacı budur: bir API tasarımı.

Testiniz, bir API tasarlama girişiminde bulunmaz. Tüm işlevselliğin dış GameOfLifesınıf içinde bulunduğu durum bilgisi olan bir sistem kurdunuz .

Bu uygulamayı yazacak olsaydım, inşa etmek istediğim parçaları düşünürdüm. Örneğin Cell, daha büyük uygulamaya geçmeden önce bir sınıf yapabilir , bunun için testler yazabilirim. Kesinlikle Conway düzgün bir şekilde uygulamak için gereken "her yönden sonsuz" veri yapısı için bir sınıf oluşturmak ve bunu test. Tüm bunlar yapıldıktan sonra, bir mainyöntemi olan genel sınıfı yazmayı düşünürdüm .

"Başarısız olan bir test yazın" adımına dikkat çekmek kolaydır. Ancak istediğiniz şekilde çalışan başarısız testi yazmak TDD'nin çekirdeğidir.


1
Bir Hücrenin sadece a için bir sargı olacağını düşünürsek boolean, bu tasarım performans için kesinlikle daha kötü olurdu. Gelecekte ikiden fazla durumu olan diğer hücresel otomata genişletilebilir olması gerekmediği sürece?
user253751

2
@immibis Bu ayrıntılar üzerinde tartışıyor. Hücre koleksiyonunu temsil eden bir sınıfla başlayabilirsiniz. Ayrıca, performansla ilgili bir sorun varsa, hücre sınıfını ve testlerini daha sonra hücre koleksiyonunu temsil eden bir sınıfla taşıyabilir / birleştirebilirsiniz.
Eric

@immibis Performans nedeniyle canlı komşu sayısı saklanabilir. Boyama nedenleriyle hücrenin hayatta kaldığı keneler ..
Blorgbeard dışarı

@immibis erken optimizasyon kötülük ... Ayrıca, ilkel takıntıdan kaçınmak, kaç eyaleti desteklese de, kaliteli kod yazmanın harika bir yoludur. Şuna bir göz atın: jamesshore.com/Blog/PrimitiveObsession.html
Paul

0

Bunun hakkında farklı düşünce okulları var.

Bazıları: test derleme hatası - gidip mevcut en küçük üretim kodunu yazın.

Bazıları Söyleyin: Önce karınca emip çekmediğini kontrol edin, sonra eksik sınıflar / yöntemler oluşturun.

İlk yaklaşımla gerçekten kırmızı-yeşil-refactor döngüsünde olursunuz. İkincisi ile elde etmek istediğiniz şeyi biraz daha geniş bir genel bakış var.

Hangi şekilde çalışacağınızı seçmek size kalmıştır. IMHO'nun her iki yaklaşımı da geçerlidir.


0

Bir şeyi "birlikte hackleme" biçiminde uygulasam bile, yine de tüm programda yer alacak sınıfları ve adımları düşünüyorum. Yani bunu düşündünüz ve bu tasarım düşüncelerini ilk önce bir test olarak yazdınız - bu harika!

Şimdi bu ilk testi gerçekleştirmek için her iki uygulamada da yinelemeyi sürdürün ve ardından tasarımı geliştirmek ve genişletmek için daha fazla test ekleyin.

Size yardımcı olabilecek şey, testlerinizi yazmak için Salatalık veya benzeri bir şey kullanmaktır .


0

Testlerinizi yazmaya başlamadan önce sisteminizi nasıl tasarlayacağınızı düşünmelisiniz. Tasarım aşamasında önemli miktarda zaman harcamalısınız. Eğer bunu yaptıysanız, TDD konusunda bu karışıklığı yaşamayacaksınız.

TDD sadece bir geliştirme yaklaşımı bağlantısıdır: TDD
1. Bir test ekleyin
2. Tüm testleri çalıştırın ve yenisinin başarısız olup olmadığına bakın
3. Bir kod yazın
4. Testleri çalıştırın
5. Refactor kodu
6. Tekrarlayın

TDD, yazılımınızı geliştirmeye başlamadan önce planladığınız tüm gerekli özellikleri karşılamanıza yardımcı olur. link: Yararları


0

Bu nedenle java veya C # ile yazılmış sistem seviyesi testlerini sevmiyorum . Spec # için c # için veya Java için salatalık tabanlı test çerçevesinden (belki JBehave) bakın. O zaman testleriniz daha çok böyle görünebilir.

resim açıklamasını buraya girin

Ve tüm sistem testlerinizi değiştirmek zorunda kalmadan nesne tasarımınızı değiştirebilirsiniz.

("Normal" birim testleri tek sınıfları test ederken harikadır.)

Java için BDD çerçeveleri arasındaki farklar nelerdir?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.