Dahili bileşenleri birim test etme


14

Bir sınıfın / modülün / paketin / vb. Dahili / özel bileşenlerini ne ölçüde test ediyorsunuz? Onları hiç test ediyor musunuz, yoksa sadece dış dünyaya olan arabirimi mi test ediyorsunuz? Bu dâhili örnek özel yöntemlerdir.

Örnek olarak, tek bir merkezi prosedürden çağrılan birkaç dahili prosedür (fonksiyon / yöntem) içeren özyinelemeli bir iniş ayrıştırıcısı düşünün . Dış dünyaya tek arayüz, bir dize alan ve ayrıştırılan bilgileri döndüren merkezi prosedürdür. Diğer prosedürler ipin farklı kısımlarını ayrıştırır ve bunlar merkezi prosedürden veya diğer prosedürlerden çağrılır.

Doğal olarak, harici arayüzü örnek dizelerle çağırarak ve elle ayrıştırılmış çıktıyla karşılaştırarak test etmelisiniz. Peki ya diğer prosedürler? Alt dizelerini doğru şekilde ayrıştırıp ayırmadıklarını kontrol etmek için tek tek test eder misiniz?

Birkaç argüman düşünebilirim:

Artıları :

  1. Daha fazla test her zaman daha iyidir ve bu kod kapsamını artırmaya yardımcı olabilir
  2. Bazı dahili bileşenler, harici arayüze giriş vererek belirli girişler (örneğin kenar durumlar) vermek zor olabilir
  3. Daha net test. Dahili bir bileşende (sabit) bir hata varsa, bu bileşen için yapılan bir test durumu, hatanın söz konusu bileşende olduğunu açıkça belirtir

Eksileri :

  1. Yeniden düzenleme çok acı verici ve zaman alıcı hale geliyor. Herhangi bir şeyi değiştirmek için, harici arayüzün kullanıcıları etkilenmese bile birim testlerini yeniden yazmanız gerekir
  2. Bazı diller ve test çerçeveleri buna izin vermiyor

Görüşleriniz neler?


olası çoğaltma veya önemli çakışma: programmers.stackexchange.com/questions/10832/…
azheglov

Yanıtlar:


8

Durum: bir "modül" (geniş anlamda, yani genel bir arayüze ve muhtemelen bazı özel iç parçalara sahip olan bir şeyin) içinde bazı karmaşık / ilgili mantık vardır. Sadece modül arayüzünün test edilmesi, modülün iç yapısına göre bir çeşit entegrasyon testi olacaktır ve bu nedenle bir hata bulunması durumunda, bu tür bir test, arızadan sorumlu olan tam iç kısmı / bileşeni yerelleştirmeyecektir.

Çözüm: Karmaşık iç parçaları modüllere dönüştürün, birim olarak test edin (ve çok karmaşıklarsa bu adımları onlar için tekrarlayın) ve orijinal modülünüze aktarın. Artık tek bir testi kolayca yapabileceğiniz bir dizi modülünüz var (hem davranışın doğru olup olmadığını kontrol edin hem de hataları düzeltin) ve hepsi bu.

Not:

  • "alt modül" ün yeni / değiştirilmiş sözleşmeyi yerine getirmek için yeterli hizmet sunmadığı sürece, modül sözleşmesini değiştirirken modülün (eski) "alt modüllerinin" testlerinde herhangi bir değişiklik yapmaya gerek kalmayacaktır.

  • hiçbir şey gereksiz yere kamuya açıklanmayacaktır, yani modülün sözleşmesi ve kapsülleme korunacaktır.

[Güncelleme]

Nesnenin iç parçalarını (özel olarak içe aktarılan modüller / paketler değil üyeler) sadece nesnenin genel arabirimi aracılığıyla girişleri besleyerek uygun duruma getirmenin zor olduğu durumlarda bazı akıllı dahili mantığı test etmek için:

  • sadece durumu içeriden ayarlayan ve davranışı istediğiniz gibi test eden arkadaşlara (C ++ terimleriyle) veya paket (Java) erişimine sahip bazı test kodlarına sahip olun.

    • bu, test amaçlı olarak iç kısımlara kolay doğrudan erişim sağlarken kapsüllemeyi bir daha kırmayacak - sadece testleri "kara kutu" olarak çalıştırın ve bunları sürüm yapılarında derleyin.

ve liste düzeni biraz kırık gibi görünüyor; (
mlvljr

1
İyi cevap. .NET'te dahili [assembly: InternalsVisibleTo("MyUnitTestAssembly")]özellikleri AssemblyInfo.cstest etmek için içindeki özniteliği kullanabilirsiniz . Yine de hile gibi geliyor.
Kimse

@rmx Bir şey gerekli tüm kriterleri karşıladığında, gerçek hilelerle ortak bir şey olsa bile hile olmaz. Ancak modüllerarası / modül içi erişim konusu, modern anaakım dillerde gerçekten biraz daha çelişkilidir.
mlvljr

2

FSM tabanlı koda yaklaşım, geleneksel olarak kullanılandan biraz farklıdır. Donanım testi için burada açıklananlara çok benzer (tipik olarak bir FSM'dir).

Kısacası, sadece belirli bir çıktı üretmekle kalmayıp aynı zamanda belirli bir "kötü" çıktı üretirken de başarısız bileşenin arızanın doğasıyla tanımlanmasına izin veren bir test girdi dizisi (veya bir dizi test girdi dizisi) oluşturursunuz. Yaklaşım oldukça ölçeklenebilir, test tasarımına ne kadar çok zaman harcarsanız test o kadar iyi olur.

Bu tür testler "fonksiyonel testler" olarak adlandırılan testlere daha yakındır, ancak bir uygulamaya her dokunduğunuzda testleri değiştirme ihtiyacını ortadan kaldırır.


2

Peki - bağlıdır :-). Bir BDD (Davranış Odaklı Geliştirme) veya ATDD (Kabul Testi Odaklı Geliştirme) yaklaşımını izliyorsanız, genel arayüzü test etmek iyidir (değişken girdilerle kapsamlı bir şekilde test ettiğiniz sürece). gerçekten önemli.

Bununla birlikte, bu algoritmanın bir kısmının belirli bir zaman dilimi içinde veya belirli bir bigO eğrisi (örn. Nlogn) boyunca yürütülmesini istediğinizi varsayalım. Bazıları buna daha çok geleneksel TDD / Birim Testi yaklaşımı diyor.

Her şeyde olduğu gibi, YMMV


1

Fonksiyonel anlam ile birden parçalara bölmek, örneğin ParseQuotedString(), ParseExpression(), ParseStatement(), ParseFile()ve onları tüm kamu olun. Sözdiziminizin o kadar çok değişmesi, bunların önemsiz hale gelme olasılığı nedir?


1
bu yaklaşım kolayca zayıf kapsülleme ve daha büyük ve kullanımı / arayüzleri daha zor hale getirir.
sara
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.