Test Odaklı Geliştirme Nasıl Yapılır


15

Uygulama geliştirmede sadece 2 yıldan fazla tecrübem var. O iki yılda kalkınmaya yaklaşımım şöyleydi:

  1. Gereksinimleri analiz edin
  2. Identity Core bileşeni / Nesneler, Gerekli fonksiyonlar, Davranış, Süreç ve kısıtlamaları
  3. Sınıflar oluşturun, aralarındaki ilişki, nesnelerin davranışı ve durumları üzerindeki kısıtlamalar
  4. İşlevler oluşturun, gereksinimlere göre davranışsal kısıtlamalarla işleyin
  5. Uygulamayı manuel olarak test et
  6. Gereksinim değişiklikleri bileşen / işlevleri değiştirirse uygulamayı manuel olarak test edin

Son zamanlarda TDD ile tanıştırıldım ve gelişmiş kodun var olması için güçlü bir neden olduğu ve dağıtım sonrası sorunların birçoğu azaltıldığı için bunun geliştirme yapmak için çok iyi bir yol olduğunu hissediyorum.

Ama benim sorunum ilk önce testler oluşturamıyorum, daha doğrusu ben bileşenleri yazıyorum ve sadece bileşenleri yazmadan önce onlar için test yazıyorum. sorum şu

  1. Doğru mu yapıyorum? Eğer tam olarak ne değiştirmem gerekiyorsa
  2. Yazdığınız sınavın yeterli olup olmadığını tespit etmenin bir yolu var mı?
  3. 1 + 1 = 2'ye eşdeğer olabilecek çok basit işlevsellik için test yazmak iyi bir uygulama mı yoksa sadece bir abartı mı?
  4. İşlevselliği değiştirmek ve buna bağlı olarak gereksinimin değişip değişmediğini test etmek iyi midir?

2
"Bileşenleri tanımlıyorum ve gerçekten bileşenleri yazmadan önce onlar için test yazıyorum.": Bunu doğru buluyorum: önce sisteminizin kaba mimarisini tanımlayıp kodlamaya başlıyorsunuz. Kodlama (TDD) sırasında, tek tek bileşenlerin ayrıntılarını hesaplarsınız ve muhtemelen mimarinizle yol boyunca çözebileceğiniz sorunları keşfedersiniz. Ama önceden analiz yapmadan kodlamaya başlamamanın iyi olduğunu düşünüyorum.
Giorgio

TDD yapmadan otomatik birim / entegrasyon testi de yapabilirsiniz . İkisi genellikle karışıktır, ancak aynı şey değildir.
Andres F.16

Yanıtlar:


19

Doğru mu yapıyorum? Eğer tam olarak ne değiştirmem gerekiyorsa

Sadece bu kısa açıklamadan söylemek zor, ama bu, hayır, şüpheli değil doğru yapıyor. Not: Yaptığınız şeyin işe yaramadığını veya bir şekilde kötü olduğunu söylemiyorum, ancak TDD yapmıyorsunuz. Orta "D", "Sürülen" anlamına gelir, testler her şeyi, geliştirme sürecini, kodu, tasarımı, mimariyi ve her şeyi yönlendirir .

Testler size ne yazacağınızı, ne zaman yazacağınızı, sonra ne yazacağınızı, ne zaman yazmayı durduracağınızı söyler. Size tasarımı ve mimariyi anlatıyorlar. (Tasarım ve mimari koddan yeniden düzenleme yoluyla ortaya çıkar.) TDD testle ilgili değildir. İlk önce testler yazmakla bile ilgili değil: TDD, testlerin sizi yönlendirmesine izin vermekle ilgilidir, önce bunları yazmak sadece gerekli bir önkoşuldur.

Kodu gerçekten yazmanızın ya da tamamen etmenizin önemi yoktur: kafanıza kod (iskelet) yazıyorsunuz, daha sonra bu kod için testler yazıyorsunuz. Bu TDD değil.

Bu alışkanlığı bırakmak zor . Gerçekten, gerçekten zor. Özellikle deneyimli programcılar için zor görünüyor.

Keith Braithwaite, TDD'yi Demek İstediğiniz Gibi adlandırdığı bir egzersiz yarattı . Kesinlikle izlemeniz gereken ve sizi TDD'yi daha titiz bir şekilde uygulamaya yönlendirecek şekilde tasarlanmış bir dizi kuraldan ( Bob Amca'nın Üç TDD Kuralına dayanır , ancak çok daha katı) oluşur. Çift programlama ile en iyi şekilde çalışır (böylece çiftiniz kuralları ihlal etmediğinizden emin olabilir) ve bir eğitmen.

Kurallar:

  1. Tam olarak yeni bir test yazın, mümkün olan en küçük test bir çözüm yönünü gösteriyor gibi görünüyor
  2. Bakın başarısız; derleme hataları hata olarak sayılır
  3. Test yönteminde yapabileceğiniz en az uygulama kodunu yazarak (1) 'den testi yapın .
  4. Yeniden çoğaltma kaldırmak için refactor, aksi takdirde tasarım geliştirmek için gerektiği gibi. Bu hareketleri kullanma konusunda katı olun:
    1. yeni bir yöntem istiyorsunuz — zamanı yeniden düzenleyene kadar bekleyin, ardından… bunlardan birini yaparak yeni (test dışı) yöntemler oluşturun ve başka bir yolla:
      • tercih edilen: test sınıfında yeni bir yöntem oluşturmak için (3) 'e göre oluşturulan uygulama kodunda Extract Method yapın veya
      • Gerekirse: (3) uyarınca uygulama kodunu mevcut bir uygulama yöntemine taşıyın
    2. yeni bir sınıf istiyorsunuz — zamanı yeniden düzenleyene kadar bekleyin, sonra… bir Taşıma Yöntemi için bir hedef sağlamak ve başka bir sebep olmadan test dışı sınıflar oluşturun
    3. Taşıma Yöntemini uygulayarak uygulama sınıflarını yöntemlerle doldurun ve başka bir yol kullanmayın

Tipik olarak, bu, kafanızda tasarımın ne olması gerektiğini hayal ederek, sıkça uygulanmış "sözde TDD yöntemi" ne göre çok farklı tasarımlara yol açacak, daha sonra bu tasarımı zorlamak için testler yazacak, daha önce tasarladığınız tasarımı uygulayacak testler".

Bir grup insan sahte TDD kullanarak tic tac toe oyunu gibi bir şey uyguladığında, genellikle Board3 × 3 Integers dizisi olan bir tür sınıf içeren çok benzer tasarımlarla sonuçlanırlar . Ve programcıların en azından bir kısmı aslında bu sınıfı testler olmadan yazmış olacaklar çünkü “buna ihtiyaç duyacaklarını biliyorlar” ya da “testlerini yazmak için bir şeye ihtiyaçları var”. Bununla birlikte, aynı grubu TDD'yi Kastettiğiniz gibi uygulamaya zorladığınızda, genellikle çok farklı tasarımların geniş bir çeşitliliği ile sonuçlanırlar, çoğu zaman a'ya benzer bir şey bile kullanmazlar Board.

Yazdığınız sınavın yeterli olup olmadığını tespit etmenin bir yolu var mı?

Tüm iş gereksinimlerini karşıladıklarında. Testler, sistem gereksinimlerinin bir kodlamasıdır.

1 + 1 = 2'ye eşdeğer olabilecek çok basit işlevsellik için test yazmak iyi bir uygulama mı yoksa sadece bir abartı mı?

Yine, geriye doğru var: işlevsellik için test yazmıyorsunuz. Testler için işlevsellik yazıyorsunuz. Testi geçmek için işlevsellik önemsiz ise, bu harika! Bir sistem gereksinimini karşıladınız ve bunun için çok çalışmak zorunda kalmadınız!

İşlevselliği değiştirmek ve buna bağlı olarak gereksinimin değişip değişmediğini test etmek iyi midir?

Hayır. Bir gereksinim değişirse, bu gereksinime karşılık gelen testi değiştirirsiniz, başarısız olduğunu izleyin, sonra geçmesi için kodu değiştirin. Testler her zaman önce gelir.

Bunu yapmak zor. Bir noktaya ulaşmak için bir çeşit "kas hafızası" oluşturmak için düzinelerce, belki de yüzlerce saatlik kasıtlı uygulamaya ihtiyacınız var , burada son tarih belirdiğinde ve baskı altındayken, bunu düşünmenize bile gerek yok ve bunu yapmak çalışmanın en hızlı ve en doğal yolu haline gelir .


1
Gerçekten çok açık bir cevap! Pratik açıdan, TDD'yi uygularken esnek ve güçlü bir test çerçevesi çok zevklidir. TDD'den bağımsız olmakla birlikte, testleri otomatik olarak yürütme yeteneği bir uygulamada hata ayıklamak için çok değerlidir. TDD'ye başlamak için, interaktif olmayan programlar (UNIX stili) muhtemelen en kolay olanıdır, çünkü bir kullanım durumu, çıkış durumu ve programın çıktısı beklenen ile karşılaştırılarak test edilebilir. Bu yaklaşımın somut bir örneği OCaml için Benzin kütüphanemde bulunabilir .
Michael Le Barbier Grünewald

4
"Aynı grubu TDD'yi Kastettiğiniz Gibi Uygulamaya zorladığınızda, genellikle çok farklı tasarımların geniş bir çeşitliliğiyle sonuçlanırlar, çoğu zaman bir Tahtaya uzaktan benzer bir şey kullanmazlar" iyi bir şeymiş gibi . Bunun iyi bir şey olduğu açık değildir ve hatta bakım açısından kötü bile olabilir, çünkü uygulama yeni birine karşı çok sezgisel olacaktır. Bu uygulama çeşitliliğinin neden iyi olduğunu veya en azından kötü olmadığını açıklayabilir misiniz?
Jim Clay

3
+1 Yanıt TDD'yi doğru olarak tanımlaması açısından iyidir. Bununla birlikte, aynı zamanda TDD'nin neden kusurlu bir metodoloji olduğunu da gösterir: özellikle algoritmik problemlerle karşılaşıldığında dikkatli düşünce ve açık tasarıma ihtiyaç vardır. Herhangi bir alan bilgisine sahip değilmiş gibi davranarak TDD'nin "kör" olarak yapılması (TDD'nin öngördüğü gibi) gereksiz zorluklara ve çıkmaz noktalara yol açar. Kötü şöhretli Sudoku çözücü çöküşüne bakın (kısa versiyon: TDD alan bilgisini yenemez).
Andres F.16

1
Tic-Tac-Toe için "sözde TDD" yaparken, onlar oluşturarak başlayın: @AndresF .: Aslında blog yazısı size bunu yürekten olursa etmek TDD 'i yaparken Keith yapılan deneyimlerini sözlerine benzer bağlantılı Boarda ile sınıf 3x3 dizisi int(veya bunun gibi bir şey). Oysa, onları TDDAIYMI yapmaya zorlarsanız, genellikle alan bilgisini yakalamak için bir mini DSL oluştururlar. Tabii ki bu sadece anekdot. İstatistiksel ve bilimsel olarak sağlam bir çalışma iyi olurdu, ancak bu tür çalışmalarda olduğu gibi, bunlar çok küçük veya çok pahalı.
Jörg W Mittag

@ JörgWMittag Seni yanlış anladıysam düzelt, ama Ron Jeffries'in "sahte TDD" yaptığını mı söylüyorsun ? Bu bir "gerçek İskoçyalı" yanılgısı değil mi? (Daha bilimsel çalışmalara ihtiyaç duyduğunuz konusunda size katılıyorum; bağlantılı olduğum blog, TDD kullanımının belirli bir örneğinin muhteşem başarısızlığı hakkında renkli bir fıkra. Ne yazık ki, TDD evangelistleri geri kalanı için çok yüksek görünüyor Bu yöntem ve bunun iddia edilen faydaları hakkında gerçek bir analiz yapmamız gerekir).
Andres F.16

5

Geliştirme yaklaşımınızı "sadece yukarıdan aşağıya" bir süreç olarak tanımlarsınız - daha yüksek bir soyutlama düzeyinden başlarsınız ve ayrıntılara giderek daha fazla girersiniz. TDD, en azından popüler olduğu haliyle, "aşağıdan yukarıya" bir tekniktir. Ve çoğunlukla "yukarıdan aşağıya" çalışan biri için "aşağıdan yukarıya" çalışmak gerçekten çok sıra dışı olabilir.

Peki, geliştirme sürecinize nasıl daha fazla "TDD" getirebilirsiniz? İlk olarak, gerçek geliştirme sürecinizin yukarıda açıkladığınız gibi her zaman "yukarıdan aşağıya" olmadığını varsayıyorum. 2. adımdan sonra, muhtemelen diğer bileşenlerden bağımsız bazı bileşenler tanımlamış olacaksınız. Bazen önce bu bileşenleri uygulamaya karar verirsiniz. Bu bileşenlerin genel API'sinin ayrıntıları muhtemelen yalnızca gereksinimlerinize uymuyor, ayrıntılar da tasarım kararlarınızı takip ediyor. TDD ile başlayabileceğiniz nokta budur: bileşeni nasıl kullanacağınızı ve gerçekte API'yı nasıl kullanacağınızı hayal edin. Ve böyle bir API kullanımını bir test şeklinde kodlamaya başladığınızda, TDD ile yeni başladınız.

İkinci olarak, daha önce "aşağıdan yukarıya" kod yazarken bile, önce var olmayan diğer bileşenlere bağımlı bileşenlerle başlayarak TDD yapabilirsiniz. Öğrenmeniz gereken şey, önce bu diğer bağımlılıkları nasıl "alay" edeceğinizdir. Bu, alt düzey bileşenlere gitmeden önce yüksek düzey bileşenler oluşturmanıza ve test etmenize olanak tanır. Ralf Westphal'ın bu blog yazısında TDD'yi yukarıdan aşağıya bir şekilde yapmaya ilişkin çok ayrıntılı bir örnek bulabilirsiniz .


3

Doğru mu yapıyorum? Eğer tam olarak ne değiştirmem gerekiyorsa

Sen gayet iyi gidiyorsun.

Yazdığınız sınavın yeterli olup olmadığını tespit etmenin bir yolu var mı?

Evet, bir test / kod kapsamı aracı kullanın . Martin Fowler test kapsamı hakkında iyi tavsiyeler sunuyor .

1 + 1 = 2'ye eşdeğer olabilecek çok basit işlevsellik için test yazmak iyi bir uygulama mı yoksa sadece bir abartı mı?

Genel olarak, bazı girdiler göz önüne alındığında bir sonuç vermeyi beklediğiniz herhangi bir işlev, yöntem, bileşen vb. Bir birim test için iyi bir adaydır. Bununla birlikte, (mühendislik) yaşamındaki çoğu şeyde olduğu gibi, ödünleşimlerinizi de dikkate almanız gerekir: Uzun vadede birim testini yazarak daha kararlı bir kod tabanıyla sonuçlanan çaba ofset mi? Genel olarak, kritik / kritik işlevsellik için önce test kodu yazmayı seçin. Daha sonra kodun test edilmemiş bazı bölümleriyle ilişkili hatalar olduğunu fark ederseniz, daha fazla test ekleyin.

İşlevselliği değiştirmek ve buna bağlı olarak gereksinimin değişip değişmediğini test etmek iyi midir?

Otomatik testlere sahip olmanın iyi yanı, bir değişikliğin önceki iddiaları ihlal edip etmediğini hemen görmenizdir. Değişen gereksinimler nedeniyle bunu beklerseniz, evet test kodunu değiştirmeniz uygundur (aslında, saf TDD'de testleri önce gereksinimlere göre değiştirirsiniz, daha sonra kodu yeni gereksinimleri karşılayana kadar kabul edersiniz).


Kod kapsamı çok güvenilir bir önlem olmayabilir. Kapsama yüzdesinin uygulanması genellikle gereksiz birçok testle sonuçlanır (tüm parametreler için boş kontroller gibi testler gibi - neredeyse hiç değer katmayan testler için testler) ve kodun test edilmesi zor olsa da, boşa harcanan geliştirme süresi yollar hiç test edilmeyebilir.
Paul

3

Yazma testleri ilk olarak yazılım yazma konusunda tamamen farklı bir yaklaşımdır. Testler sadece uygun kod işlevselliği doğrulamasının (hepsi geçer) bir aracı değil, aynı zamanda tasarımı tanımlayan güçtür. Test kapsamı yararlı bir metrik olsa da, kendi başına hedef olmamalıdır - TDD'nin amacı kod kapsamının% 'sine ulaşmak değil, kodunuzu yazmadan önce test edilebilirliğini düşünmektir.

İlk önce yazma testleri ile ilgili sorunlarınız varsa, TDD'de deneyimli biriyle çift programlama oturumu yapmanızı şiddetle tavsiye ederim, böylece tüm yaklaşım hakkında "düşünme yolu" deneyimini öğrenirsiniz.

Yapılması gereken bir diğer iyi şey ise, ilk satırdan TDD kullanılarak yazılımın geliştirildiği çevrimiçi videoyu izlemek. Bir zamanlar kendimi TDD ile tanıştırmak için kullandığım iyi olan James Shore'nin Let's Play TDD'siydi . Bir göz atın, ortaya çıkan tasarımın nasıl çalıştığını, testler yazarken kendinize hangi soruları sormanız gerektiğini ve yeni sınıfların ve yöntemlerin nasıl oluşturulduğunu, yeniden düzenlendiğini ve yinelendiğini gösterecektir.

Yazdığınız sınavın yeterli olup olmadığını tespit etmenin bir yolu var mı?

Bunun sorulması yanlış soru olduğuna inanıyorum. TDD'yi yaptığınızda, yazılım yazmanın yolu olarak TDD'yi ve ortaya çıkan tasarımı yapmayı seçtiniz. Eklemeniz gereken yeni işlevler her zaman bir testle başlarsa, her zaman orada olacaktır.

1 + 1 = 2'ye eşdeğer olabilecek çok basit işlevsellik için test yazmak iyi bir uygulama mı yoksa sadece bir abartı mı?

Açıkçası bağlıdır, kararınızı kullanın. Yöntem genel API'nın bir parçası değilse, parametreler üzerinde boş denetimler yazmamayı tercih ederim, ancak aksi halde, Add (a, b) yönteminin gerçekten bir + b döndürdüğünü neden onaylamıyorsunuz?

İşlevselliği değiştirmek ve buna bağlı olarak gereksinimin değişip değişmediğini test etmek iyi midir?

Yine, kodunuzu değiştirdiğinizde veya yeni işlevsellik eklediğinizde, ister yeni bir test eklesin, ister gereksinimler değiştiğinde mevcut olanı değiştirin, bir teste başlarsınız.

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.