Gerçekten bir birim test çerçevesine ihtiyacım var mı?


19

Şu anda işimde, C ++ uygulamamız için geniş bir birim test paketimiz var. Ancak birim test çerçevesi kullanmıyoruz. Temelde bir iddiayı ve bir coutu saran bir C makrosu kullanırlar. Gibi bir şey:

VERIFY(cond) if (!(cond)) {std::cout << "unit test failed at " << __FILE__ << "," << __LINE__; asserst(false)}

Sonra testlerimizin her biri için

void CheckBehaviorYWhenXHappens()
{
    // a bunch of code to run the test
    //
    VERIFY(blah != blah2);
    // more VERIFY's as needed
}

CI sunucumuz "birim testi başarısız oldu" ifadesini alıyor ve mesajı geliştiricilere e-postayla göndererek derleme başarısız oluyor.

Yinelenen kurulum kodumuz varsa, bunu üretimde sahip olacağımız diğer yinelenen kodlarda olduğu gibi yeniden düzenleriz. Yardımcı fonksiyonların arkasına sarıyoruz, bazı test sınıflarının sık kullanılan senaryoları ayarlamasını sağlıyoruz.

CppUnit ve boost birim testi gibi çerçeveler olduğunu biliyorum. Acaba bu değerler ne katıyor? Bunların masaya getirdiklerini özlüyor muyum? Onlardan kazanabileceğim yararlı bir şey var mı? Özellikle sahip olduğumuz şey basit ve iyi çalışıyor gibi göründüğü için gerçek değer katmadıkça bir bağımlılık eklemekte tereddüt ediyorum.

Yanıtlar:


8

Diğerlerinin söylediği gibi, zaten kendi, basit, ev yapımı çerçeveniz var.

Bir tane yapmak önemsiz gibi görünüyor. Bununla birlikte, birim test çerçevesinin uygulanması o kadar kolay olmayan başka bazı özellikleri de vardır, çünkü bunlar dil hakkında ileri düzeyde bilgi sahibi olurlar. Genellikle bir test çerçevesinden istediğim ve homebrew için o kadar kolay olmayan özellikler şunlardır:

  • Test senaryolarının otomatik toplanması. Yeni test yöntemini tanımlamak, onu çalıştırmak için yeterli olmalıdır. JUnit, adları ile başlayan tüm yöntemleri otomatik olarak toplar test, NUnit [Test]ek açıklamasına sahiptir, Boost.Test BOOST_AUTO_TEST_CASEve BOOST_FIXTURE_TEST_CASEmakrolarını kullanır .

    Çoğunlukla kolaylık, ancak elde edebileceğiniz her kolaylık, geliştiricilerin gerçekten yapmaları gereken testleri yazma ve bunları doğru bir şekilde bağlama şansını artırır. Uzun talimatlarınız varsa, birileri şimdi bir kısmını özleyecek ve belki de bazı testler yapılmayacak ve kimse fark etmeyecek.

  • Kodu test etmeden ve yeniden derlemeden seçilen test senaryolarını çalıştırabilme. İyi bir birim test çerçevesi, komut satırında hangi testleri çalıştırmak istediğinizi belirtmenize olanak tanır. Birim testlerinde hata ayıklamak istiyorsanız (birçok geliştirici için en önemli nokta), her yerde kod değiştirmeden çalıştırmak için sadece bazılarını seçebilmeniz gerekir.

    Diyelim ki # 4211 hata raporu aldınız ve birim testi ile çoğaltılabilir. Yani bir tane yazıyorsunuz, ancak koşucuya sadece bu testi çalıştırmasını söylemeniz gerek, böylece orada gerçekten neyin yanlış olduğunu ayıklayabilirsiniz.

  • Testlerin kendisinde değişiklik yapmadan, test senaryosu başına beklenen hataları test edebilme. Aslında bunu elde etmek için çerçeveleri değiştirdik.

    Herhangi bir düzgün boyutlu test takımında, test ettikleri özellikler henüz uygulanmadığı için başarısız olan testler olacaktır, henüz kimsenin bunları düzeltmek için zamanı yoktu. Testleri beklenen hatalar olarak işaretleme yeteneği olmadan, düzenli olarak bazı başka hatalar fark edemezsiniz, bu nedenle testler ana amaçlarına hizmet etmeyi bırakır.


teşekkürler bence bu en iyi cevap. Şu anda makrom işini yapıyor, ancak bahsettiğiniz özelliklerin hiçbirini yapamıyorum.
Doug T.

1
@Jan Hudec "Bu çoğunlukla kolaylıktır, ancak elde edebileceğiniz her kolaylık, geliştiricilerin gerçekten yapmaları gereken testleri yazmalarını ve bunları doğru bir şekilde bağlamalarını sağlar."; Tüm test çerçeveleri (1) kurulum için önemsizdir, genellikle güncel geçerli talimatlardan daha eski veya ayrıntılı olmayan kurulum talimatlarına sahiptir; (2) doğrudan bir test çerçevesine bağlı kalırsanız, ortada bir arayüz olmadan, onunla evlisiniz, çerçeveleri değiştirmek her zaman kolay değildir.
Dmitry

@Jan Hudec Daha fazla kişinin birim testleri yazmasını beklersek, Google'da "Birim Testi Nedir" için "Birim Testi Nedir" den daha fazla sonuç almamız gerekir. Bir Birim Testinin herhangi bir Birim Test Çerçevesinden veya Birim Test tanımından bağımsız olduğunu bilmiyorsanız Birim Testi yapmanın bir anlamı yoktur. Birim Testi'nin ne olduğuyla ilgili güçlü bir anlayışa sahip değilseniz Birim Testi yapamazsınız, aksi takdirde Birim Testi yapmanın bir anlamı yoktur.
Dmitry

Bu kolaylık argümanını almıyorum. Örneklerin önemsiz dünyasından ayrılırsanız test kodu yazmak çok zordur. Tüm bu maketler, kurulumlar, kütüphaneler, harici maket sunucu programları vb. Hepsi test çerçevesini içten dışa bilmenizi gerektirir.
Lothar

@Lothar, evet, çok fazla iş ve öğrenmesi gereken çok şey var, ancak yine de tekrar tekrar basit bir kazan yazmak zorundasınız, çünkü birkaç yararlı yardımcı programdan yoksunsanız işiniz daha az hoş olur ve bu da verimlilikte fark edilir bir fark yaratır.
Jan Hudec

27

Zaten bir çerçeve, ev yapımı bir çerçeve kullandığınız anlaşılıyor.

Daha popüler çerçevelerin katma değeri nedir? Ekledikleri değerin, şirketiniz dışındaki kişilerle kod değişimi yapmanız gerektiğinde bunu yapabileceğinizi söyleyebilirim, çünkü bilinen ve yaygın olarak kullanılan çerçeveye dayanmaktadır .

Ev yapımı bir çerçeve ise, kodunuzu asla paylaşmanıza veya çerçevenin kendisinin büyümesini zorlaştıracak çerçevenin kendisini sağlamaya zorlar.

Kodunuzu, herhangi bir açıklama ve birim test çerçevesi olmadan bir meslektaşınıza olduğu gibi verirseniz, derleyemez.

Ev yapımı çerçevelerin ikinci bir dezavantajı uyumluluktur . Popüler birim test çerçeveleri, farklı IDE'ler, sürüm kontrol sistemleri vb. yeni bir IDE veya yeni bir VCS? Tekerleği yeniden keşfedecek misiniz?

Son olarak, daha büyük çerçeveler, bir gün kendi çerçevenizde uygulamanız gerekebilecek daha fazla özellik sağlar . Assert.AreEqual(expected, actual)her zaman yeterli değildir. Gerekirse:

  • hassasiyeti ölçmek?

    Assert.AreEqual(3.1415926535897932384626433832795, actual, 25)
    
  • çok uzun süre çalışırsa geçersiz test? Zaman aşımını yeniden uygulamak, eşzamansız programlamayı kolaylaştıran dillerde bile kolay olmayabilir.

  • bir istisna atılmasını bekliyor bir yöntem test?

  • daha zarif bir kod var mı?

    Assert.Verify(a == null);
    

    iyi, ancak bunun yerine bir sonraki satırı yazma niyetiniz daha anlamlı değil mi?

    Assert.IsNull(a);
    

Kullandığımız "çerçeve" çok küçük bir başlık dosyasındadır ve iddia semantiğini takip eder. Bu yüzden listelediğiniz dezavantajlar konusunda fazla endişelenmiyorum.
Doug T.

4
Deneyleri test çerçevesinin en önemsiz parçası olarak görüyorum. Test senaryolarını toplayan ve çalıştıran ve sonuçları kontrol eden koşucu önemsiz olmayan önemli kısımdır.
Jan Hudec

@Jan tam takip etmiyorum. Koşucum, her C ++ programı için ortak bir rutin. Birim test çerçevesi koşucusu daha karmaşık ve kullanışlı bir şey yapıyor mu?
Doug T.

1
Çerçeveniz yalnızca ana yöntemle onaylama ve testlerin semantiğine izin verir ... şimdiye kadar. Ödevlerinizi birden fazla senaryo halinde gruplamak, başlatılmış verilere dayalı olarak birlikte gruplandırmak vb. Kadar bekleyin
James Kingsbery

@DougT .: Evet, iyi bir birim test çerçevesi koşucusu daha sofistike bazı yararlı şeyler yapar. Tam cevabımı görün.
Jan Hudec

4

Diğerlerinin söylediği gibi, zaten kendi evinizdeki çerçeveye sahipsiniz.

Başka bir test çerçevesi kullanmak için görebilmemin tek nedeni endüstri "ortak bilgisi" açısından olacaktır. Yeni geliştiriciler ev yapımı yolunuzu öğrenmek zorunda kalmayacaktı (yine de çok basit görünüyor).

Ayrıca, diğer test çerçeveleri yararlanabileceğiniz daha fazla özelliğe sahip olabilir.


1
Kabul. Mevcut test stratejinizle sınırlı kalmıyorsanız, değiştirmek için çok az neden görüyorum. İyi bir çerçeve muhtemelen daha iyi organizasyon ve raporlama yetenekleri sağlar, ancak kod tabanınızla (derleme sisteminiz dahil) entegrasyon için gereken ek işleri gerekçelendirmeniz gerekir.
TMN

3

Basit bir çerçeve olsa bile zaten bir çerçeveniz var.

Onları gördüğüm gibi daha büyük bir çerçevenin ana avantajları, birçok farklı türde iddiayı (yükseltme iddiaları gibi), birim testlerine mantıklı bir siparişi ve sadece bir zaman. Ayrıca, örneğin, setUP () ve tearDown () yöntemini uygularsanız, xUnit testlerinin desenini takip etmek oldukça iyidir. Tabii ki, bu sizi söz konusu çerçeveye kilitler. Bazı çerçevelerin diğerlerinden daha iyi alay entegrasyonuna sahip olduğunu unutmayın - örneğin google alay ve test.

Tüm birim testlerinizi yeni bir çerçevede yeniden düzenlemeniz ne kadar sürer? Günler veya birkaç hafta belki buna değer ama daha fazla belki de çok fazla değil.


2

Gördüğüm gibi, ikinizin de avantajı var ve siz de "dezavantajlı "sınız.

Avantajı, kendinizi rahat hissettiğiniz ve sizin için çalışan bir sisteme sahip olmanızdır. Ürününüzün geçerliliğini doğruladığından memnunsunuz ve muhtemelen farklı bir çerçeve kullanan bir şey için tüm testlerinizi değiştirmeye çalışırken hiçbir iş değeri bulamazsınız. Kodunuzu yeniden düzenleyebiliyorsanız ve testleriniz değişiklikleri alırsa - ya da daha iyisi, testlerinizi değiştirebilirseniz ve mevcut kodunuz yeniden yapılanana kadar testleri geçemezse, tüm tabanlarınız kapsanır. Ancak...

İyi tasarlanmış bir birim test API'sine sahip olmanın avantajlarından biri, modern IDE'lerin çoğunda çok sayıda yerel desteğin olmasıdır. Bu, sabit çekirdekli VI'yı etkilemez ve orada Visual Studio kullanıcılarını küçümseyen kullanıcıları emacs eder, ancak iyi bir IDE kullanan kullanıcılar için testlerinizi hata ayıklama ve bunları içinde yürütme olanağınız vardır. IDE'nin kendisi. Bu iyidir, ancak kullandığınız çerçeveye bağlı olarak daha da büyük bir avantaj vardır ve bu, kodunuzu test etmek için kullanılan dildir .

Dil söylediğimde , bir programlama dilinden bahsetmiyorum, ama bunun yerine, test kodunu bir hikaye gibi okumasını sağlayan akıcı bir sözdizimine sarılmış zengin bir set kelimeden bahsediyorum. Özellikle, BDD çerçevelerinin kullanımı için bir savunucu oldum . Benim kişisel favori DotNet BDD API'sıdır StoryQ, ancak aynı temel amaca sahip, gereksinimler belgesinden bir kavram çıkarmak ve spesifikasyonda nasıl yazıldığına benzer bir şekilde kod yazmaktır. Bununla birlikte, gerçekten iyi API'ler, bir testteki her bir ifadeyi ele geçirerek ve bu ifadenin başarılı bir şekilde çalışıp çalışmadığını veya başarısız olup olmadığını belirterek daha da ileri gider. Bu, tüm testi erken dönmeden yürüttüğünüz için inanılmaz derecede kullanışlıdır, yani hata ayıklama çabalarınız inanılmaz derecede verimli olur, çünkü dikkatinizi tüm testin kodunu çözmenize gerek kalmadan testin başarısız olan kısımlarına odaklamanız gerekir. sıra. Diğer güzel şey, test çıktısının size tüm bu bilgileri göstermesidir,

Neden bahsettiğimin bir örneği olarak aşağıdakileri karşılaştırın:

Ekleri Kullanma:

Assert(variable_A == expected_value_1); // if this fails...
Assert(variable_B == expected_value_2); // ...this will not execute
Assert(variable_C == expected_value_3); // ...and nor will this!

Akıcı bir BDD API kullanarak: (İtalik bitlerin temel olarak yöntem işaretçileri olduğunu düşünün)

WithScenario("Test Scenario")
    .Given(*AConfiguration*) // each method
    .When(*MyMethodToTestIsCalledWith*, variable_A, variable_B, variable_C) // in the
    .Then(*ExpectVariableAEquals*, expected_value_1) // Scenario will
        .And(*ExpectVariableBEquals*, expected_value_2) // indicate if it has
        .And(*ExpectVariableCEquals*, expected_value_3) // passed or failed execution.
    .Execute();

Şimdi BDD sözdiziminin daha uzun ve daha kötü olduğu ve bu örneklerin korkunç şekilde yapıldığını, ancak belirli bir sistem davranışı sonucunda bir sistemde çok şeyin değiştiği çok karmaşık test durumları için BDD sözdizimi size net bir şekilde sunuyor neyi test ettiğinizi ve test yapılandırmanızın nasıl tanımlandığını gösteren bir açıklama içerir ve bu kodu programcı olmayan bir kişiye gösterebilirsiniz. Buna ek olarak, "değişken_A" her iki durumda da sınamayı geçemezse, Asserts örneği sorunu düzeltene kadar ilk onaylayıcıdan sonra yürütülmezken, BDD API zincirde çağrılan her yöntemi yürütür ve ifadenin münferit bölümleri hatalıydı.

Şahsen bu yaklaşımın, test dilinin müşterilerinizin mantıksal gereksinimlerinden bahsedeceği dil ile aynı olması bakımından daha geleneksel xUnit çerçevelerinden daha iyi çalıştığını düşünüyorum. Buna rağmen, çabalarımı desteklemek için eksiksiz bir test API'sı icat etmeye gerek kalmadan xUnit çerçevelerini benzer bir tarzda kullanmayı başardım ve iddialar hala etkili bir şekilde kısa devre yapacak olsa da, daha temiz okuyorlar. Örneğin:

Nunit Kullanımı :

[Test]
void TestMyMethod()
{
    const int theExpectedValue = someValue;

    GivenASetupToTestMyMethod();

    var theActualValue = WhenIExecuteMyMethodToTest();

    Assert.That(theActualValue, Is.EqualTo(theExpectedValue)); // nice, but it's not BDD
}

Bir birim test API'sı kullanarak keşfetmeye karar verirseniz, tavsiyem kısa bir süre için çok sayıda farklı API ile deneme yapmak ve yaklaşımınızı açık tutmaktır. Ben BDD'yi kişisel olarak savunurken, kendi iş ihtiyaçlarınız ekibinizin koşulları için farklı bir şey gerektirebilir. Ancak anahtar, mevcut sisteminizi ikinci olarak tahmin etmekten kaçınmaktır. Gerekirse, mevcut testlerinizi her zaman başka bir API kullanarak birkaç testle destekleyebilirsiniz, ancak kesinlikle her şeyi aynı yapmak için büyük bir test yeniden yazılmasını önermem. Eski kod kullanımdan düştükçe, onu ve testlerini yeni bir kodla ve alternatif bir API kullanarak testlerle kolayca değiştirebilirsiniz ve bu, size herhangi bir gerçek iş değeri vermeyecek büyük bir çabaya yatırım yapmanıza gerek kalmadan. Birim test API'sini kullanma konusunda,


1

Sahip olduğunuz basit ve işi bitiriyor. Eğer senin için işe yarıyorsa, harika. Bir ana ünite test çerçevesine ihtiyacınız yoktur ve mevcut bir birim test kütüphanesini yeni bir çerçeveye taşıma çalışmalarına gitmek için tereddüt ederim. Birim test çerçevelerinin en büyük değerinin giriş engelini azaltmak olduğunu düşünüyorum; sadece testler yazmaya başlıyorsunuz, çünkü çerçeve zaten mevcut. Bu noktayı geçtiniz, bu yüzden bu avantajdan yararlanamayacaksınız.

Ana akım bir çerçeveyi kullanmanın diğer yararı - ve bu küçük bir fayda, IMO - yeni geliştiricilerin kullandığınız çerçeveyi zaten hızlandırmış olmaları ve daha az eğitim gerektirmeleri. Uygulamada, tarif ettiğiniz gibi basit bir yaklaşımla, bu çok önemli olmamalıdır.

Ayrıca, çoğu ana çerçeve, çerçevenizin sahip olabileceği veya olmayabileceği belirli özelliklere sahiptir. Bu özellikler tesisat kodunu azaltır ve test senaryolarının yazılmasını daha hızlı ve kolay hale getirir:

  • Adlandırma kuralları, ek açıklamalar / özellikler vb. Kullanılarak test senaryolarının otomatik olarak çalıştırılması.
  • Çeşitli daha spesifik iddialar, böylece tüm iddialarınız için koşullu mantık yazmak veya türlerini iddia etmek için istisnaları yakalamak zorunda değilsiniz.
  • Test senaryolarının sınıflandırılması, böylece bunların alt kümelerini kolayca çalıştırabilirsiniz.
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.