Ünite testleri tam olarak alay konusu olmadan nasıl yazılmalıdır?


80

Anladığım kadarıyla, birim testlerinin amacı , kod birimlerini ayrı ayrı test etmek . Bu şu demek:

  1. Kod tabanında başka herhangi bir ilgisiz kod değişikliğinden kaçmamalıdırlar .
  2. Sadece bir ünite testi, test ünitesindeki bir entegrasyon testinin aksine (yığınlar halinde kırılabilir) bir hatayla kırılmalıdır.

Tüm bunlar, test edilen bir birimin her dış bağımlılığının, alay edilmesi gerektiği anlamına gelir. Ve tüm dış bağımlılıkları kastediyorum , sadece ağ, dosya sistemi, veritabanı gibi "dış katmanları" değil.

Bu, neredeyse her birim testinin alay etmek zorunda olduğu mantıklı bir sonuca yol açar . Öte yandan, alay etmekle ilgili hızlı bir Google araştırması, "alay etmenin bir kod kokusu" olduğunu iddia eden ve çoğunlukla (tamamen olmasa da) kaçınılması gerektiğini söyleyen tonlarca makaleyi ortaya koymaktadır.

Şimdi, soru (lar) a.

  1. Ünite testleri nasıl doğru şekilde yazılmalıdır?
  2. Bunlarla entegrasyon testleri arasındaki çizgi tam olarak nerede yatıyor?

Güncelleme 1

Lütfen aşağıdaki sahte kodu göz önünde bulundurun:

class Person {
    constructor(calculator) {}

    calculate(a, b) {
        const sum = this.calculator.add(a, b);

        // do some other stuff with the `sum`
    }
}

Bağımlılığı engellemeden Person.calculatemetodu test eden bir test Calculator(verilen, Calculator“dış dünyaya erişmeyen hafif bir sınıf olduğu göz önüne alındığında) bir birim testi olarak kabul edilebilir mi?


10
Bunun bir kısmı zamanla gelecek olan sadece tasarım tecrübesidir. Bileşenlerinizi nasıl yapılandıracağınızı öğreneceksiniz, böylelikle onların bağımlılıklarını aşması zor olmadıkları için Bu, test edilebilirliğin, herhangi bir yazılımın ikincil tasarım hedefi olması gerektiği anlamına gelir. Bu amaç, testin kodla birlikte veya kodla birlikte yazılması durumunda, örneğin TDD ve / veya BDD kullanılarak karşılanması daha kolaydır.
amon

33
Hızlı ve güvenilir bir şekilde çalışan testleri bir klasöre yerleştirin. Yavaş ve potansiyel olarak kırılgan olan testleri bir başkasına yerleştirin. Testleri ilk klasörde mümkün olduğunca sık çalıştırın (kelimenin tam anlamıyla, yazmaya her ara verdiğinizde ve kod derlendiğinde her zaman idealdir, ancak tüm geliştirme ortamları bunu desteklemez). Daha yavaş testleri daha az çalıştırın (örneğin kahve molası verdiğinizde). Birim ve entegrasyon adları hakkında endişelenmeyin. İsterseniz hızlı ve yavaş bir şekilde arayın. Önemli değil.
David Arno

6
“Neredeyse her birim testinin alay etmesi gerekiyor” Evet, öyle mi? "alay etmekle ilgili hızlı bir Google araması," alay etmenin bir kod kokusu "olduğunu iddia eden makalelerin tonlarca yanlış olduğunu ortaya koyuyor .
Michael

13
@Michael Basitçe 'evet, öyleyse' ifade etmek ve karşıt görüşü yanlış ilan etmek, böyle çekişmeli bir konuya yaklaşmanın harika bir yolu değildir. Belki de bir cevap yazıp alaycılığın neden her yerde olması gerektiğini ve belki de 'tonlarca makale'nin neden yanlış olduğunu düşündüğünüzü açıklayın.
AJFaraday

6
"Alay etmek bir kod kokusu" hakkında bir alıntı yapmadığınız için, sadece okuduğunuz şeyi yanlış yorumladığınızı tahmin edebilirim. Alay etmek kod kokusu değil. Sahtekarlıkları enjekte etmek için yansıma veya diğer shenaniganların kullanılması ihtiyacı bir kod kokusudur. Alay etmenin zorluğu, API tasarımınızın kalitesiyle ters orantılıdır. Yapıcılara alay ileten basit basit birim testleri yazıyorsanız, doğru şekilde yapıyorsunuz demektir.
TKK

Yanıtlar:


59

Birim testlerinin amacı, kod birimlerini yalıtımlı olarak test etmektir.

Martin Fowler Birim Testi

Birim testi genellikle yazılım geliştirmede konuşulur ve tüm zaman boyunca programları yazarken aşina olduğum bir terimdir. Bununla birlikte, çoğu yazılım geliştirme terminolojisi gibi, bu çok kötü tanımlanmamıştır ve insanların gerçekte olduğundan daha sıkı bir şekilde tanımlandığını düşündüklerinde, kafa karışıklığının sıklıkla yaşandığını görüyorum.

Kent Beck, Test Odaklı Gelişimde Örnek Yazılıyla Ne Yazdı?

Onlara "birim testleri" diyorum, ancak birim testlerinin kabul edilen tanımlarına pek uymuyorlar

Herhangi bir “birim test noktası” olduğu iddiası, büyük ölçüde “birim test” tanımının dikkate alındığına bağlı olacaktır.

Bakış açınız programınız birbirine bağlı birçok küçük birimlerden oluşuyorsa ve kendinizi her bir birimi ayrı ayrı test eden bir stille sınırlandırıyorsanız, birçok test çifti kaçınılmaz bir sonuçtur.

Gördüğünüz çelişkili tavsiye, farklı varsayımlar altında çalışan insanlardan geliyor.

Örneğin, yeniden geliştirme sürecinde geliştiricileri desteklemek için testler yazıyorsanız ve bir birimi ikiye böldüğünüzde, desteklenmesi gereken bir yeniden düzenleme işlemidir , o zaman bir şeyler vermeniz gerekir. Belki bu tür bir test farklı bir isme ihtiyaç duyar? Ya da belki farklı bir "birim" anlayışına ihtiyacımız var.

Karşılaştırma yapmak isteyebilirsiniz:

Hesap makinesi bağımlılığını alay etmeden Person.calculate yöntemini test eden bir test (verilen, Hesap Makinesi'nin "dış dünyaya" erişmeyen hafif bir sınıftır) birim testi olarak kabul edilebilir mi?

Bence sorulması gereken yanlış soru; asıl önemsediğimiz şeyin özellik olduğuna inandığımda yine etiketler hakkındaki bir argüman .

Kodda değişiklikler yaparken, testlerin izolasyonunu umursamıyorum - zaten "yanlış" ın geçerli onaylanmamış düzenlemeler yığımda bir yerde olduğunu biliyorum. Sık sık testleri yaparsam, o zaman yığının derinliğini sınırlandırırım ve hatayı bulmak önemsizdir (aşırı durumda, testler her düzenlemeden sonra çalıştırılır - yığının maksimum derinliği birdir). Ancak testleri yapmak amaç değildir - bu bir kesintidir - bu yüzden kesinti etkisinin azaltılmasında değer vardır. Kesintiyi azaltmanın bir yolu, testlerin hızlı olmasını sağlamaktır ( Gary Bernhardt, 300ms’i öneriyor , ancak benim durumumda bunun nasıl yapılacağını çözmedim).

Eğer çağrı Calculator::addyapmak testi çalıştırmak için gereken süreyi önemli ölçüde arttırmazsa (veya bu kullanım durumunun diğer önemli özelliklerinden herhangi birini), o zaman bir test çifte kullanmakla uğraşmazdım - bu maliyetlerden daha ağır faydalar sağlamaz .

Buradaki iki varsayıma dikkat edin: maliyet değerlendirmesinin bir parçası olarak bir insan ve fayda değerlendirmesinde doğrulanmamış değişikliklerin kısa bir yığını. Bu koşulların geçerli olmadığı durumlarda “izolasyon” un değeri biraz değişmektedir.

Ayrıca bkz. Sıcak Perva , Harry Percival.


5
yapar eklemek alay o hesap kanıtlamak olduğunu tek şey olabilir (bu da başka yollarla kontrol edilebilir olsa da) tasarım çift kişi ve hesap yok olduğunu yani alay
jk.

40

Ünite testleri tam olarak alay konusu olmadan nasıl yazılmalıdır?

Kodunuzdaki yan etkileri en aza indirerek.

Örnek kodunuzu alarak, örneğin calculatorbir web API ile konuşursa, o zaman bu web API ile etkileşime girmeye dayanan kırılgan testler yaratırsınız veya bir sahtekarlık yaratırsınız. Bununla birlikte, deterministik, devletsiz bir hesaplama işlevi kümesi varsa, bununla alay etmeyin (ve yapmamalısınız). Bunu yaparsanız, testinizde hatalara yol açan sahte kodunuzun gerçek koda farklı davranma riskiyle karşı karşıya kalırsınız.

Sadece dosya sistemine okuyan / yazan kod, veritabanları, URL bitiş noktaları vb. altında bulunduğunuz ortama bağlı olanlar; ya da bu, doğada oldukça kararlı ve belirleyici değildir. Bu nedenle, kodun bu bölümlerini minimumda tutarsanız ve bunları soyutlamaların arkasına gizlerseniz, taklit edilmesi kolaydır ve kodunuzun geri kalanı sahte gerekliliğinden kaçınır.

Yan etkileri olan kod noktaları için, alay eden testler yazmayan testlere değmez. İkincisi, doğal olarak kırılgan ve muhtemelen yavaş olacakları için özen göstermeleri gerekir. Bu nedenle, kodunuzu her kaydettiğinizde ve oluşturduğunuzda, yalnızca bir gecede bir CI sunucusunda söylemelerini isteyebilirsiniz. Ancak eski testler mümkün olduğunca sık yapılmalıdır. Her testin bir birim veya entegrasyon testi olup olmadığına gelince, akademik hale gelir ve birim testin ne olduğu ve ne olmadığı üzerine “alev savaşları” yapılmasını önler.


8
Bu hem pratikte hem de anlamsız bir anlamsal tartışmadan kaçınmak için doğru cevaptır.
Jared Smith,

Böyle bir stili kullanan ve hala iyi bir test kapsamı olan önemsiz bir açık kaynaklı kod temeli örneği var mı?
Joeri Sebrechts

4
@JoeriSebrechts her bir tek FP olanı? Örnek
Jared Smith,

Tam olarak aradığım şey değil, çünkü sadece birbirinden bağımsız bir fonksiyonlar topluluğu, birbirini adlandıran bir fonksiyonlar sistemi değil. Eğer bu fonksiyon en üst seviyelerden biriyse, test etmek amacıyla bir fonksiyon için karmaşık argümanlar oluşturma zorunluluğunu nasıl yaşarsınız? Örneğin, bir oyunun çekirdek döngüsü.
Joeri Sebrechts

1
@JoeriSebrechts hmm, ya ne istediğinizi yanlış anlıyorum ya da verdiğim örneğe yeterince derin kazmadınız. Ramda fonksiyonları, kaynaklarındaki yerin her yerinde dahili çağrıları kullanır (örn. R.equals). Bunlar çoğunlukla saf fonksiyonlar oldukları için, genellikle testlerde alay edilmezler.
Jared Smith

31

Bu sorular zorluklarında oldukça farklıdır. Önce 2. soruyu alalım.

Birim testleri ve entegrasyon testleri açıkça ayrılmıştır. Bir birim testi bir birimi (yöntem veya sınıf) test eder ve diğer birimleri yalnızca bu hedefe ulaşmak için gereken kadar kullanır. Alay etmek gerekli olabilir, ancak testin amacı bu değil. Bir entegrasyon testi, farklı gerçek birimler arasındaki etkileşimi test eder . Bu fark, hem birim hem de entegrasyon testine ihtiyaç duymamızın nedeninin tümüdür - biri diğerinin işini yeterince iyi yaptıysa, bunu yapmamamız gerekirdi, ancak genelleştirilmiş bir araç yerine iki özel araç kullanmanın genellikle daha verimli olduğu ortaya çıktı. .

Şimdi önemli soru için: Ünite testini nasıl yapmalısınız? Yukarıda belirtildiği gibi, birim testleri, yalnızca gerektiği kadar yardımcı yapılar inşa etmelidir . Genellikle sahte bir veritabanı kullanmak, gerçek veritabanınızdan veya herhangi bir gerçek veritabanınızdan daha kolaydır . Bununla birlikte, kendi içinde alay etmenin bir değeri yoktur. Sık sık ortaya çıkarsa, aslında orta seviye ünite testi için girdi olarak başka bir katmanın gerçek bileşenlerini kullanmak daha kolaydır . Eğer öyleyse, kullanmaktan çekinmeyin.

Birçok uygulayıcı, ünite testi B, ünite testi A tarafından zaten test edilmiş olan sınıfları yeniden kullanırsa, ünite A'daki bir hatanın birden fazla yerde test başarısızlığına neden olduğundan korkar. Ben bir problem bu düşünün: Bir test paketi başarılı olmalı % 100 size ihtiyacınız güvence vermek amacıyla, yüzden çok fazla arızaları var büyük bir sorun değil - sonuçta sen bunu bir kusur var. Tek kritik sorun, bir hatanın çok az arızaya neden olması durumunda olacaktır .

Bu nedenle, alaycı bir din yapmayın. Bu bir amaç değil, bir amaçtır, bu yüzden ekstra çabadan kaçınmaktan kurtulursanız, yapmalısınız.


4
The only critical problem would be if a defect triggered too few failures.bu, alaycılığın zayıf noktalarından biridir. Beklenen davranışı "programlamak" zorundayız, bu yüzden başarısızlıkla sonuçlanabilir ve testlerimizin "yanlış pozitif" olarak bitmesine neden olabiliriz. Ancak, alaycılık determinism (testin en önemli koşulu) elde etmek için çok faydalı bir tekniktir. Bunları mümkün olduğunda tüm projelerimde kullanıyorum. Ayrıca, entegrasyonun ne kadar karmaşık veya bağımlılığın çok sıkı olduğunu da gösteriyorlar.
Laiv

1
Test edilen bir ünite başka birimler kullanıyorsa, gerçekten bir entegrasyon testi değil mi? Çünkü özünde bu ünite, söz konusu üniteler arasındaki etkileşimi, tam bir entegrasyon testinde olduğu gibi test ediyor olacaktır.
Alexander Lomia

11
@AlexanderLomia: Birim olarak ne adlandırırsınız? 'String' de bir birim olarak adlandırır mısın? İsterdim, ama bununla alay etmeyi hayal etmem.
Bart van Ingen Schenau

5
" Birim testleri ve entegrasyon testleri açıkça ayrılmıştır. Birim testi bir birimi (yöntem veya sınıf) test eder ve diğer birimleri yalnızca bu hedefe ulaşmak için gereken kadar kullanır ". İşte ovmak. Bu sizin birim test tanımınız. Benimki oldukça farklı. Dolayısıyla, aralarındaki fark, herhangi bir tanım için sadece "açıkça ayrılmıştır", fakat ayrıştırma, tanımlar arasında değişir.
David Arno

4
@Voo Bu tür kod tabanlarıyla çalışmış olsanız da, asıl sorunu bulmak sıkıntı yaratabilse de (özellikle mimari hata ayıklamak için kullanacağınız şeyleri boyandıysa), Test etmek için kullandıkları kodun ardından çalışmaya devam etme testleri kesildi.
James_pic

6

Tamam, doğrudan sorularınızı yanıtlamak için:

Ünite testleri nasıl doğru şekilde yazılmalıdır?

Söylediğiniz gibi, bağımlılıkları alay etmeli ve sadece söz konusu üniteyi test etmelisiniz.

Entegrasyon testleri ile aralarındaki çizgi tam olarak nerede yatıyor?

Entegrasyon testi, bağımlılıklarınızın alay edilmediği bir birim testidir.

Hesaplayıcıyı alay etmeden Person.calculate yöntemini test eden bir test bir birim testi olarak kabul edilebilir mi?

Hayır. Hesap makinesi bağımlılığını bu koda enjekte etmeniz gerekir ve sahte bir versiyon ile gerçek versiyon arasında seçim yapabilirsiniz. Alaycı bir test kullanıyorsanız, bir test, gerçek sınav kullanıyorsanız bir bütünleştirme testi.

Ancak, bir uyarı. İnsanların testlerinin ne yapılması gerektiğini düşündüğünü gerçekten umursuyor musun?

Ancak asıl sorunuz şu gibi görünüyor:

alay etmekle ilgili hızlı bir Google araştırması, "alay etmenin bir kod kokusu" olduğunu iddia eden ve çoğunlukla (tamamen olmasa da) kaçınılması gereken birçok makaleyi ortaya koymaktadır.

Bence buradaki problem, birçok insanın bağımlılıkları tamamen yeniden yaratmak için alay kullandıklarıdır. Örneğin, hesap makinenizi örneğin

public class MockCalc : ICalculator
{
     public Add(int a, int b) { return 4; }
}

Ben böyle bir şey yapmazdım:

myMock = Mock<ICalculator>().Add((a,b) => {return a + b;})
myPerson.Calculate()
Assert.WasCalled(myMock.Add());

Bunun "sahtekarlığı sınamak" ya da "uygulamayı sınamak" olacağını iddia ediyorum. " Mocks yazma! * Böyle " derdim .

Diğer insanlar da benimle aynı fikirde değillerdi. Bloglarımızda, Mock’un En İyi Yolu’na dair büyük alev savaşları başlatacaktık. Bu, çeşitli yaklaşımların tüm geçmişini anlamadığınız ve gerçekten çok fazla değer vermediğiniz sürece hiçbir anlam ifade etmeyecek sadece iyi testler yazmak isteyen birine.


Ayrıntılı bir cevap için teşekkür ederiz. Diğer insanların testlerim hakkında ne düşündüklerini umursamadan - aslında proje ilerledikçe güvenilmez bir karışıklık haline gelebilecek yarı entegrasyon, yarı birim testleri yazmaktan kaçınmak istiyorum.
Alexander Lomia

Prob yok, bence sorun, iki şeyin tanımlarının herkes tarafından% 100 kabul edilmemesidir.
Ewan

Ben senin sınıfı yeniden adlandırmak istiyorum MockCalciçin StubCalcve bir saplama değil sahte diyoruz. martinfowler.com/articles/…
bdsl

@bdsl Bu makale 15 yaşında
Ewan

4
  1. Ünite testleri nasıl yapılmalıdır?

Temel kuralm şu ki uygun birim testleri:

  • Uygulamalara değil arayüzlere karşı kodlanmıştır . Bunun birçok faydası var. İlk olarak, bu sınıflar uygulamalarını sağlar Bağımlılık Inversion Principle gelen KATI . Ayrıca, bu diğer sınıfların da yaptığını ( değil mi? ) Yani testlerin de aynı şeyi yapmalı. Ayrıca, test kodunun çoğunu tekrar kullanırken aynı arabirimin birden fazla uygulamasını test etmenize izin verir (yalnızca başlatma ve bazı iddialar değişebilir).
  • Kendi kendine yeten var . Söylediğiniz gibi, herhangi bir dış koddaki değişiklikler test sonucunu etkileyemez. Bu nedenle, birim testleri inşa sırasında gerçekleştirilebilir. Bu, herhangi bir yan etkiyi gidermek için alaylara ihtiyacınız olduğu anlamına gelir. Ancak, Bağımlılık İnversiyon Prensibi'ni izliyorsanız, bu nispeten kolay olmalıdır. Spock gibi iyi test çerçeveleri , minimum kodlama ile testlerde kullanılacak herhangi bir arabirimin sahte uygulamalarını dinamik olarak sağlamak için kullanılabilir. Bu, her test sınıfının yalnızca tam olarak bir uygulama sınıfından artı test çerçevesinin (ve belki de model sınıflarının ["fasulye"]) kodunu kullanması gerektiği anlamına gelir .
  • Ayrı çalışan bir uygulama gerektirmez . Testin bir şeyle konuşması gerekiyorsa, bir veritabanı veya web servisi olsun, bu bir birim testi değil, bir entegrasyon testidir. Çizgiyi ağ bağlantılarında veya dosya sisteminde çiziyorum. Örneğin tamamen hafızada tutulan bir SQLite veritabanı, gerçekten ihtiyacınız varsa, bir test için bence adil bir oyundur.

Birim testini zorlaştıran çerçevelerden faydalı sınıflar varsa, bu bağımlılıklarla alay etmeyi kolaylaştırmak için çok basit bir "sarmalayıcı" arayüzleri ve sınıfları oluşturmayı bile faydalı bulabilirsiniz. Bu sarmalayıcılar daha sonra mutlaka birim testlerine tabi tutulmayacaktır.

  1. [Birim testleri] ile entegrasyon testleri arasındaki çizgi tam olarak nerede yatıyor?

Bu ayrımı en faydalı buldum:

  • Birim testleri , uygulama sınıflarının istenen davranış ve kod düzeyi arabirimlerinin anlamsal davranışlarına karşı davranışını doğrulayarak "kullanıcı kodunu" simüle eder .
  • Entegrasyon testleri kullanıcıyı çalıştırarak çalışan uygulamanın belirtilen kullanım durumlarına ve / veya resmi API'lere karşı davranışını doğrular . Bir web servisi için "kullanıcı" bir istemci uygulaması olacaktır.

Burada gri alan var. Örneğin, bir Docker kabında bir uygulama çalıştırabilir ve entegrasyon testlerini bir yapının son aşaması olarak çalıştırabilir ve daha sonra kabı imha edebilirseniz, bu testleri "birim testleri" olarak dahil etmek doğru olur mu? Eğer bu senin yanan tartışmansa, çok iyi bir yerdesin.

  1. Hemen hemen her birim testinin alay etmesi gerektiği doğru mu?

Hayır. Bazı bireysel test durumları, nullparametre olarak geçmek ve bir istisna olduğunu doğrulamak gibi hata durumları için olacaktır . Bunun gibi birçok test alay gerektirmez. Ayrıca, dize işleme veya matematik işlevleri gibi hiçbir yan etkisi olmayan uygulamalar, çıktıyı doğruladığınız için herhangi bir alay gerektirmeyebilir. Ancak, en değerli derslerin, test kodunda bir yerde en az bir deneme gerektireceğini düşünüyorum. (Ne kadar az, o kadar iyi.)

Bahsettiğiniz "kod kokusu" sorunu, aşırı karmaşık bir sınıfa sahip olduğunuzda ortaya çıkar, bu da testlerinizi yazmak için uzun bir alay bağımlılığı listesi gerektirir. Bu, her bir sınıfın daha küçük bir ayakizine ve daha net bir sorumluluğa sahip olması ve bu nedenle daha kolay test edilebilir olması için uygulamayı yeniden yapılandırmanız ve işleri bölmeniz gereken bir ipucudur. Bu, uzun vadede kaliteyi artıracaktır.

Sadece bir ünite testi, test edilen ünitede bir hata ile kırılmalıdır.

Bunun makul bir beklenti olduğunu sanmıyorum, çünkü yeniden kullanıma karşı çalışıyor. privateÖrneğin, publicarabiriminiz tarafından yayınlanan birden çok yöntem tarafından adlandırılan bir yöntem olabilir . Bu yöntemde ortaya çıkan bir hata daha sonra birden fazla test hatasına neden olabilir. Bu, aynı kodu her publicyönteme kopyalamanız gerektiği anlamına gelmez .


3
  1. Kod tabanında başka herhangi bir ilgisiz kod değişikliğinden kaçmamalıdırlar .

Bu kuralın ne kadar yararlı olduğundan emin değilim. Bir sınıfta / yöntemde bir değişiklik olursa, bir başkasının davranışını üretim kodunda bozabilirse, işler gerçekte ortak çalışanlardır ve ilgisizdir. Testleriniz bozulursa ve üretim kodunuz bozulmazsa, testleriniz şüphelidir.

  1. Sadece bir ünite testi, test ünitesindeki bir entegrasyon testinin aksine (yığınlar halinde kırılabilir) bir hatayla kırılmalıdır.

Bu kuralı da şüpheyle kabul ediyorum. Kodunuzu yapılandırmak ve testlerinizi bir hata tam olarak bir ünite testinin başarısız olmasına neden olacak şekilde yazmak için yeterince iyiyseniz, O zaman kod bankası sizin durumunuzu kullanmaya başladığında bile tüm potansiyel hataları tanımladığınızı söylüyorsunuz. beklemiyordum.

Entegrasyon testleri ile aralarındaki çizgi tam olarak nerede yatıyor?

Bunun önemli bir ayrım olduğunu sanmıyorum. Her nasılsa bir kod birimi nedir?

Kod seviyesinin uğraştığı sorun alanı / işletme kuralları açısından sadece 'mantıklı' olan testleri yazabileceğiniz giriş noktaları bulmaya çalışın . Genellikle bu testler doğada bir şekilde 'işlevseldir' - bir girdi koyun ve çıktının beklendiği gibi olduğunu test edin. Testler sistemin istenen bir davranışını ifade ederse, üretim kodu geliştikçe ve yeniden düzenlendiğinde bile, genellikle oldukça kararlı kalırlar.

Ünite testleri tam olarak alay konusu olmadan nasıl yazılmalıdır?

'Birim' kelimesini fazla okuma ve gerçek test sınıflarını testlerde kullanmaya yatkın ol, eğer bunlardan bir tanesine birden fazla şey dahil ediyorsan endişelenmeden. Bunlardan birinin kullanımı zorsa (çünkü çok fazla başlatma gerektirir veya gerçek bir veritabanına / e-posta sunucusuna vb. Basması gerekir), o zaman düşüncelerinizi alaycı / sahte hale getirin.


Herhangi bir şekilde 'kod birimi' nedir? ” Çok iyi bir soru, kimin cevap verdiğine bağlı olabilecek beklenmedik cevapları olabilir. Tipik olarak, birim testlerin çoğu tanımı onları bir yöntem veya sınıfla ilgili olarak açıklar, ancak bu her durumda bir "birim" için gerçekten yararlı bir ölçü değildir. Bir Person:tellStory()yönteme sahip olursam, bir kişinin ayrıntılarını bir dizgiye eklerse, onu döndürür, o zaman "hikaye" muhtemelen bir birimdir. Bazı kodları gizleyen özel bir yardımcı yöntem kullanırsam, o zaman yeni bir birim kullandığımı sanmıyorum - bunu ayrı ayrı test etmem gerekmiyor.
VLAZ

1

İlk olarak, bazı tanımlar:

Bir birim testi, birimleri diğer birimlerden izole edilmiş olarak test eder, ancak bunun anlamı herhangi bir yetkili kaynak tarafından somut olarak tanımlanmaz, bu yüzden onu biraz daha iyi tanımlayalım: G / Ç sınırları aşılmışsa (G / Ç'nin ağ olup olmadığı, disk, ekran veya UI girişi), çizgi çizebileceğimiz yarı objektif bir yer var. Kod G / Ç'ye bağlıysa, bir birim sınırını geçiyor ve bu nedenle bu G / Ç'den sorumlu birimi alay etmesi gerekecek.

Bu tanım altında, saf fonksiyonlar gibi şeylerle alay etmek için zorlayıcı bir neden görmüyorum, yani birim testinin saf fonksiyonlara ya da yan etkileri olmayan fonksiyonlara yol açtığı anlamına geliyor.

Efektli test birimlerini birleştirmek istiyorsanız, efektlerden sorumlu birimler alay edilmelidir, ancak bunun yerine belki de bir entegrasyon testi düşünmelisiniz. Bu yüzden kısa cevap: "Alay etmek istersen, gerçekten ihtiyacın olan şeyin bir entegrasyon testi olup olmadığını sor." Fakat burada daha iyi, daha uzun cevaplar var ve tavşan deliği çok daha derinlere iniyor. Alaycı benim en sevdiğim kod kokusu olabilir, çünkü onlardan öğrenecek çok şey var.

Kod Kokuyor

Bunun için Wikipedia'ya döneceğiz:

Bilgisayar programlamasında, bir kod kokusu, daha derin bir sorunu gösteren bir programın kaynak kodundaki herhangi bir özelliktir.

Daha sonra devam eder ...

"Kokular, koddaki temel tasarım ilkelerinin ihlal edildiğini gösteren ve tasarım kalitesini olumsuz yönde etkileyen belirli yapılardır". Suryanarayana, Girish (Kasım 2014). Yazılım Tasarım Kokuları için Refactoring. Morgan Kaufmann. s. 258.

Kod kokuları genellikle böcek değildir; teknik olarak hatalı değiller ve programın çalışmasını engellemiyorlar. Bunun yerine, tasarımdaki gelişimi yavaşlatabilen veya gelecekte hata ya da başarısızlık riskini artırabilecek zayıflıkları belirtir.

Başka bir deyişle, tüm kod kokuları kötü değildir. Bunun yerine, bir şeyin en uygun biçimde ifade edilemeyeceğine dair ortak göstergelerdir ve koku , söz konusu kodu geliştirme fırsatı gösterebilir.

Alay etme durumunda, koku, alay çağrısı yapan birimlerin alay edilecek birimlere bağlı olduğunu gösterir. Biz atomik-çözülebilir parçalar halinde sorunu çürümüş değil bir gösterge olabilir ve bu yazılımda bir tasarım hatasını gösterebilir.

Tüm yazılım geliştirmenin özü, büyük bir problemi daha küçük, bağımsız parçalara ayırma (ayrıştırma) ve çözümleri, büyük problemi çözen bir uygulama (kompozisyon) oluşturmak için bir araya getirme sürecidir.

Büyük problemi daha küçük parçalara bölmek için kullanılan birimler birbirine bağlıyken alay gerekir. Başka bir deyişle, sözde atomik bileşim birimlerimiz gerçekten atomik olmadığında ve alay etme stratejimiz daha büyük problemi çözülecek daha küçük ve bağımsız problemlere parçalayamadığında alaycı gerekir .

Bir kodla alay etmeyi koklayan şey, alayla ilgili doğal olarak yanlış bir şey olmadığı değildir - bazen çok yararlıdır. Kod kokusu yapan şey, uygulamanızda problemli bir bağlantı kaynağı olduğunu göstermesidir. Bazen bu bağlantı kaynağını kaldırmak, sahte yazmaktan çok daha verimlidir.

Birçok bağlantı türü vardır ve bazıları diğerlerinden daha iyidir. Alayların bir kod kokusu olduğunu anlamak , koku daha kötü bir şey haline gelmeden önce , uygulama tasarım yaşam döngüsünün başındaki en kötü türleri tespit etmeyi ve bunlardan kaçınmayı öğretebilir .


0

Alay etmek, ünite testlerinde bile sadece son çare olarak kullanılmalıdır.

Bir yöntem bir birim değildir ve bir sınıf bile bir birim değildir. Birim, ne dediğinize bakmaksızın, mantıklı bir kod ayrımıdır. İyi bir şekilde test edilmiş bir koda sahip olmanın önemli bir unsuru serbestçe yeniden denetleyebilmektir ve serbestçe yeniden denetleyebilmenin bir parçası, bunu yapmak için testlerinizi değiştirmek zorunda kalmayacağınız anlamına gelir. Ne kadar alay ediyorsanız, yeniden ateşlenirken testlerinizi o kadar çok değiştirmek zorundasınız. Eğer metodu ünite olarak düşünürseniz, her yeniden denemeyi yaptığınızda testlerinizi değiştirmeniz gerekir. Ve üniteyi sınıf olarak görürseniz, bir sınıfı bir sınıfa bölmek istediğinizde testlerinizi değiştirmeniz gerekir. Kodunuzu yeniden düzenlemek için testlerinizi yeniden düzenlemek zorunda kaldığınızda, insanların kodlarını yeniden düzenlememeyi seçmelerini sağlar, bu da bir projenin başına gelebilecek en kötü şeydir. Testlerinizi yeniden düzenlemek zorunda kalmadan bir sınıfı birden fazla sınıfa ayırabilmeniz veya son derece büyük 500 sıra spagetti sınıfına girmeniz çok önemlidir. Birim test yöntemlerini veya sınıflarını birimleriniz gibi görüyorsanız, muhtemelen Nesneye Yönelik Programlama değil, nesnelerle bir çeşit mutant işlevsel programlama yapıyorsunuzdur.

Bir birim testi için kodunuzu yalıtmak, bunun dışındaki her şeyi alay ettiğiniz anlamına gelmez. Öyle olsaydı, dilinizin Math dersiyle alay etmek zorunda kalırdınız ve kesinlikle bunun iyi bir fikir olduğunu kimse düşünmez. İç bağımlılıklar, harici bağımlılıklardan farklı olarak ele alınmamalıdır. İyi sınandıklarına ve olması gerektiği gibi çalıştıklarına güveniyorsunuz. Tek gerçek fark, eğer içsel bağımlılıklarınız modüllerinizi kırıyorsa, GitHub'a bir sorun göndermek yerine düzeltmek için yaptığınız işi düzeltmek yerine düzeltmek için yaptıklarınızı durdurabilir ve düzeltmek istemediğiniz bir kod tabanına kazabilirsiniz. ya da en iyisini ümit ediyorum.

Kodunuzu yalıtmak, yalnızca iç bağımlılıklarınıza kara kutular gibi davranmanız ve bunların içinde olanları sınamadığınız anlamına gelir. 1, 2 veya 3 girişlerini kabul eden B Modülüne sahipseniz ve onu çağıran Modül A'ya sahipseniz, Modül A için yaptığınız testleri bu seçeneklerin her birini yapmanız gerekmez, sadece bir tanesini seçip kullanın. Bu, Modül A için yaptığınız testlerin, B Modülünden aldığınız yanıtları ele aldığınız farklı şekilleri test etmesi gerektiği anlamına gelir.

Bu nedenle, denetleyiciniz karmaşık bir nesnede bir bağımlılığa geçerse ve bu bağımlılık birkaç olası şey yaparsa, belki de veritabanına kaydedebilir ve belki de çeşitli hatalar döndürebilir, ancak aslında tüm denetleyicinizin geri dönüp dönmediğini kontrol etmek yeterlidir. Bir hata olsun ya da olmasın ve bu bilgiyi iletin, o zaman kontrol cihazınızda test ettiğiniz tek şey bir hata döndürüp döndürmediği ve bir hata döndürmezse bir testtir. Veritabanına bir şey kaydedilip kaydedilmediğini veya hatanın ne tür bir hata olduğunu test edemezsiniz, çünkü bu bir entegrasyon testi olacaktır. Bunu yapmak için bağımlılıkla alay etmek zorunda değilsiniz. Kodu izole ettin.

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.