Birim testi geçersiz yöntemler?


170

Hiçbir şey döndürmeyen bir yöntemi test etmenin en iyi yolu nedir? Özellikle c #.

Ne gerçekten test etmeye çalışıyorum bir günlük dosyası alır ve belirli dizeler için ayrıştırır bir yöntemdir. Dizeler daha sonra bir veritabanına eklenir. Daha önce yapılmamış bir şey değil ama TDD için ÇOK yeni olmak Bunu test etmek mümkün mü yoksa gerçekten test edilmemiş bir şey mi merak ediyorum.


55
Yaptığınız şey bu değilse lütfen "TDD" terimini kullanmayın. TDD yerine Birim Testi yapıyorsunuz. TDD yapsaydınız, asla "bir yöntemi nasıl test edersiniz" gibi bir sorunuz olmazdı. Test önce var olacaktı, sonra soru "bu testten nasıl geçilir?" Ama eğer TDD yapıyor olsaydınız, kodunuz test için yazılır (tam tersi değil) ve esas olarak kendi sorunuzu cevaplarsınız. Kodunuz TDD'nin sonucu olarak farklı biçimlendirilir ve bu sorun hiç oluşmaz. Sadece açıklığa kavuşturmak.
Suamere

Yanıtlar:


152

Bir yöntem herhangi bir şey döndürmezse, aşağıdakilerden biri

  • Emir Kipi - Nesneden kendisine bir şey yapmasını istiyorsun .. örneğin durumu değiştir (herhangi bir onay beklemeden .. bunun yapılacağı varsayılır)
  • bilgilendirme - sadece birisine bir şeyin olduğunu bildirmek (eylem veya yanıt beklemeden).

Zorunlu yöntemler - görevin gerçekten gerçekleştirilip gerçekleştirilmediğini doğrulayabilirsiniz. Durum değişikliğinin gerçekten olup olmadığını doğrulayın. Örneğin

void DeductFromBalance( dAmount ) 

denge mesajının bu mesajın gerçekten dAmount tarafından ilk değerden düşük olup olmadığını doğrulayarak test edilebilir

Bilgilendirme yöntemleri - nesnenin genel arayüzünün bir üyesi olarak nadirdir ... bu nedenle normalde birim test edilmez. Ancak, gerekiyorsa, bir bildirimde yapılacak işlemin yapılıp yapılmadığını doğrulayabilirsiniz. Örneğin

void OnAccountDebit( dAmount )  // emails account holder with info

e-postanın gönderilip gönderilmediğini doğrulayarak test edilebilir

Gerçek yönteminiz hakkında daha fazla ayrıntı yayınlayın, insanlar daha iyi cevap verebilir.
Güncelleme : Metodunuz 2 şey yapıyor. Aslında bunu bağımsız olarak test edilebilecek iki yönteme böldüm.

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

String [], ilk yönteme kukla bir dosya ve beklenen dizeler sağlayarak kolayca doğrulanabilir. İkincisi biraz zor .. DB taklit etmek veya gerçek DB vurmak ve dizeleri doğru konuma yerleştirilip yerleştirilmediğini doğrulamak için bir Mock (google veya alaycı çerçevelerde arama stackoverflow) kullanabilirsiniz. Bazı iyi kitaplar için bu konuyu kontrol edin ... Eğer bir çatırtı iseniz Pragmatik Birim Testi tavsiye ediyorum.
Kodda şu şekilde kullanılır:

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );

1
hey gishu, iyi cevap. Verdiğiniz örnek ... daha fazla Entegrasyon Testi değil mi? ve eğer öyleyse, soru hala devam ediyor, bir kimse Void Yöntemlerini gerçekten nasıl test ediyor ... belki imkansız?
andy

2
@andy - 'entegrasyon testleri' tanımınıza bağlıdır. Zorunlu yöntemler genellikle durumu değiştirir, böylece nesnenin durumunu sorgulayan bir birim testi ile doğrulanabilirsin. Bilgilendirme yöntemleri, test konusunun doğru bildirimi yayınladığından emin olmak için bir sahte dinleyiciye / ortak çalışana takılan bir birim testi ile doğrulanabilir. Her ikisinin de birim testlerle makul testler yapılabileceğini düşünüyorum.
Gishu

@andy veritabanı bir erişimci arabirimi tarafından alay edilebilir / ayrılabilir, böylece eylemin sahte nesneye iletilen veriler tarafından test edilmesine izin verilir.
Peter Geiger

62

Yan etkilerini test edin. Bu içerir:

  • Herhangi bir istisna atıyor mu? (Olması gerekiyorsa, yaptıklarını kontrol edin. Olmaması gerekiyorsa, dikkatli değilseniz bazı köşe durumlarını deneyin - null argümanlar en bariz şeydir.)
  • Parametreleriyle iyi oynuyor mu? (Değişebilirlerse, olmaması gerektiğinde onları mutasyona uğratırlar mı?
  • Üzerinde aradığınız nesnenin / türün durumu üzerinde doğru etkisi var mı?

Elbette, ne kadar test edebileceğinizin bir sınırı var . Örneğin, olası her girişle genellikle test yapamazsınız. Pragmatik bir şekilde test edin - kodunuzun uygun şekilde tasarlandığından ve doğru bir şekilde uygulandığından emin olmanız için yeterli ve bir arayanın bekleyebileceğine dair ek belgeler olarak hareket etmek için yeterli.


31

Her zaman olduğu gibi: yöntemin ne yapması gerektiğini test edin!

Küresel durumu değiştirmeli mi (uuh, kod kokusu!)

Bir arayüze çağırmalı mı?

Yanlış parametrelerle çağrıldığında bir istisna atmalı mı?

Doğru parametrelerle çağrıldığında bir istisna oluşturmamalı mı?

Olmalı mı ...?


11

Geçersiz dönüş türleri / Altyordamlar eski haberlerdir. Ben 8 yıl içinde (Ben son derece tembel olmadıkça) bir Void dönüş türü yapmadım (Bu cevaptan itibaren, bu soru sorulmadan sadece biraz önce).

Gibi bir yöntem yerine:

public void SendEmailToCustomer()

Microsoft'un int.TryParse () paradigmasını izleyen bir yöntem oluşturun:

public bool TrySendEmailToCustomer()

Belki de yönteminizin uzun vadede kullanım için geri vermesi gereken herhangi bir bilgi yoktur, ancak yöntem işini yaptıktan sonra durumunu döndürmek arayan için büyük bir kullanımdır.

Ayrıca, tek durum bool değildir. Önceden yapılmış bir Alt Programın aslında üç veya daha fazla farklı durumu (İyi, Normal, Kötü vb.) Döndürmesi birkaç kez olabilir. Bu durumlarda, sadece

public StateEnum TrySendEmailToCustomer()

Bununla birlikte, Try-Paradigm, geçersiz bir dönüşün nasıl test edileceği hakkındaki bu soruyu bir şekilde cevaplasa da, başka hususlar da vardır. Örneğin, bir "TDD" döngüsü sırasında / sonrasında, "Yeniden Düzenleme" olur ve yönteminizle iki şey yaptığınızı fark edersiniz ... böylece "Tek Sorumluluk İlkesi" ni ihlal edersiniz. Bu yüzden ilk önce ilgilenilmelidir. İkinci olarak, bir bağımlılık tanımlamış olabilirsiniz ... "Kalıcı" Verilere dokunuyorsunuz.

Söz konusu yöntemdeki veri erişimi öğelerini yapıyorsanız, n katmanlı veya n katmanlı bir mimariye yeniden bakmanız gerekir. Ancak "Dizeler daha sonra bir veritabanına eklenir" derken, aslında bir iş mantığı katmanı veya başka bir şey çağırdığınızı varsayabiliriz. Ya, varsayalım.

Nesneniz başlatıldığında, artık nesnenizin bağımlılıkları olduğunu anlıyorsunuz. Bu, Nesneye veya Yönteme Bağımlılık Enjeksiyonu yapıp yapmayacağınıza karar vermeniz gerektiğidir. Bu, Yapıcı'nızın veya söz konusu yöntemin yeni bir Parametreye ihtiyacı olduğu anlamına gelir:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

Artık işletme / veri katmanı nesnenizin bir arayüzünü kabul edebileceğinize göre, Birim Testleri sırasında bunu taklit edebilir ve "Kazayla" entegrasyon testi bağımlılığı veya korkusu olmayabilir.

Canlı kodunuzda GERÇEK bir IBusinessDataEtcnesneye geçersiniz . Ancak Birim Testinizde bir MOCK IBusinessDataEtcnesnesini geçirirsiniz . Bu Mock'ta, int XMethodWasCalledCountarabirim yöntemleri çağrıldığında durumları güncellenen gibi Arabirim Dışı Özellikler ekleyebilirsiniz .

Bu yüzden Birim Testiniz, Sorularınızdaki Yöntem (ler) inizden geçecek, sahip oldukları mantığı gerçekleştirecek ve IBusinessDataEtcnesnenizde bir veya iki veya seçilen bir yöntem kümesini çağıracaktır . Birim Testinizin sonunda İddialarınızı yaptığınızda, şimdi test etmeniz gereken birkaç şey var.

  1. Şimdi bir Try-Paradigma yöntemi olan "Altyordam" ın Durumu.
  2. Sahte IBusinessDataEtcnesnenizin durumu.

İnşaat Seviyesinde Bağımlılık Enjeksiyonu fikirleri hakkında daha fazla bilgi için ... Birim Testi ile ilgili olarak ... Builder tasarım modellerine bakın. Sahip olduğunuz her mevcut arabirim / sınıf için bir arabirim ve sınıf daha ekler, ancak bunlar çok küçüktür ve daha iyi Birim Testi için BÜYÜK işlevsellik artışları sağlar.


Bu harika cevabın ilk öbeği, tüm acemi / orta düzey programcılar için şaşırtıcı genel tavsiyeler olarak hizmet eder.
pimbrouwers

böyle bir şey olmamalı public void sendEmailToCustomer() throws UndeliveredMailExceptionmı?
A.Emad

1
@ A.Emad Güzel soru, ama hayır. İstisnaları atmaya güvenerek kodunuzun akışını kontrol etmek uzun süredir bilinen kötü bir uygulamadır. Bununla birlikte, voidyöntemlerde, özellikle Nesne Odaklı dillerde, tek gerçek seçenek olmuştur. Microsoft'un en eski alternatifi, tartıştığım Try-Paradigma ve Monads / Maybes gibi İşlevsel stil paradigmalarıdır. Bu nedenle, Komutlar (CQS'de), atmaya dayanmak yerine değerli durum bilgilerini döndürebilir, bu da GOTO(Kötü olduğunu bildiğimiz). fırlatma (ve git) yavaş, hata ayıklaması zor ve iyi bir uygulama değildir.
Suamere

Bunu temizlediğiniz için teşekkürler. C # 'a özgü mü yoksa Java ve C ++ gibi dillerde bile istisnalar atmak kötü bir uygulama mıdır?
A.Emad

9

Bunu dene:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}

1
Bu gerekli olmamalı, ancak böyle yapılabilir
Nathan Alard

StackOverflow'a hoş geldiniz! Lütfen kodunuza bir açıklama eklemeyi düşünün. Teşekkür ederim.
Aurasphere

2
ExpectedAttributeDaha net Bu testi yapmak için tasarlanmıştır.
Martin Liversage

8

Hatta bu şekilde deneyebilirsiniz:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}

1
Sanırım bu en basit yol.
Navin Pandit

5

bir nesne üzerinde bazı etkisi olacaktır .... etkisi sonucu sorgu. Görünür bir etkisi yoksa, birim testine değmez!


4

Muhtemelen yöntem bir şey yapar ve sadece geri dönmez?

Durumun böyle olduğunu varsayarsak, o zaman:

  1. Sahip nesnesinin durumunu değiştirirse, durumun doğru şekilde değişip değişmediğini test etmelisiniz.
  2. Bir nesneyi parametre olarak alır ve bu nesneyi değiştirirse, nesnenin doğru şekilde değiştirildiğini test etmelisiniz.
  3. İstisnalar atarsa ​​belirli durumlar söz konusuysa, bu istisnaların doğru atıldığını test edin.
  4. Davranışı kendi nesnesinin durumuna veya başka bir nesneye bağlı olarak değişirse, durumu önceden ayarlayın ve yöntemin yukarıdaki üç test yönteminden biriyle doğru olduğunu test edin).

Yöntemin ne yaptığını bize bildirirseniz, daha spesifik olabilirim.


3

Beklenecek çağrıları, eylemleri ve istisnaları ayarlamak için Rhino Mocks'ı kullanın . Yöntemin bazı bölümlerini alay edebileceğiniz veya saplayabileceğinizi varsayarsak. Burada yöntem, hatta bağlam hakkında bazı özellikleri bilmeden bilmek zor.


1
Ünite testinin nasıl yapılacağının cevabı asla bunu sizin için yapan bir üçüncü taraf aracı elde etmemelidir. Bununla birlikte, bir kişi testin nasıl yapılacağını bildiğinde, kolaylaştırmak için üçüncü taraf bir araç kullanmak kabul edilebilir.
Suamere

2

Ne yaptığına bağlı. Parametreleri varsa, daha sonra doğru parametre kümesiyle çağrılıp çağrılmadığını sorabileceğiniz alaylara geçin.


Kabul edildi - yöntemi test eden alayların davranışını doğrulamak bir yol olacaktır.
Jeff Schumacher

0

Void yöntemini çağırmak için hangi örneği kullanırsanız kullanın,Verfiy

Örneğin:

Benim durumumda bu _Logbir örnek ve LogMessagetest edilecek yöntem:

try
{
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch 
{
    Assert.IsFalse(ex is Moq.MockException);
}

Verifynedeniyle Test Fail olur yöntemin başarısızlığa bir istisna atar?

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.