Birim testinde yeniyim ve sürekli olarak çok fazla atılmış 'sahte nesneler' kelimelerini duyuyorum. Layman'ın terimleriyle, birisi sahte nesnelerin ne olduğunu ve birim testleri yazarken genellikle ne için kullanıldığını açıklayabilir mi?
Birim testinde yeniyim ve sürekli olarak çok fazla atılmış 'sahte nesneler' kelimelerini duyuyorum. Layman'ın terimleriyle, birisi sahte nesnelerin ne olduğunu ve birim testleri yazarken genellikle ne için kullanıldığını açıklayabilir mi?
Yanıtlar:
Birim sınamasında yeni olduğunuzu ve "layman'ın terimleriyle" sahte nesneler istediğini söylediğiniz için, bir layman örneğini deneyeceğim.
Bu sistem için birim testini hayal edin:
cook <- waiter <- customer
Aşağıdaki gibi düşük seviyeli bir bileşeni test etmeyi öngörmek genellikle kolaydır cook
:
cook <- test driver
Test sürücüsü sadece farklı yemekler sipariş eder ve aşçının her sipariş için doğru yemeği döndürdüğünü doğrular.
Garson gibi, diğer bileşenlerin davranışlarını kullanan orta bir bileşeni test etmek daha zordur. Saf bir test cihazı, garson bileşenini pişirme bileşenini test ettiğimiz şekilde test edebilir:
cook <- waiter <- test driver
Test sürücüsü farklı yemekler sipariş eder ve garsonun doğru yemeği döndürmesini sağlar. Ne yazık ki, bu, garson bileşeninin bu testinin aşçı bileşeninin doğru davranışına bağlı olabileceği anlamına gelir. Aşçı bileşeninin belirleyici olmayan davranışlar (menüde şefin bir yemek olarak sürprizini içerir), çok fazla bağımlılık (aşçı tüm personeli olmadan yemek yapmaz) veya çok fazla gibi test dostu olmayan özellikler varsa bu bağımlılık daha da kötü (bazı yemekler pahalı malzemeler gerektirir veya pişmesi bir saat sürer).
Bu bir garson testi olduğu için, ideal olarak, aşçı değil, sadece garsonu test etmek istiyoruz. Özellikle, garsonun müşterinin siparişini aşçıya doğru bir şekilde ilettiğinden ve aşçının yiyeceklerini müşteriye doğru bir şekilde verdiğinden emin olmak istiyoruz.
Birim testi, birimleri bağımsız olarak test etmek anlamına gelir, bu nedenle Fowler'ın test iki katına çıkardığı (aptallar, taslaklar, sahte ürünler, sahte ) test edilen bileşeni (garson) izole etmek daha iyi bir yaklaşım olacaktır .
-----------------------
| |
v |
test cook <- waiter <- test driver
Burada, test aşçı test sürücüsü ile "katotlarda". İdeal olarak, test edilen sistem, test aşçısının, üretim kodunu değiştirmeden (örn. Garson kodunu değiştirmeden) garsonla çalışmak üzere kolayca ikame edilebilmesi ( enjekte edilmesi ) için tasarlanmıştır .
Şimdi, test aşçısı (test double) farklı şekillerde uygulanabilir:
Sahteler ve saplamalar vs taklitler ve aptallar hakkında daha fazla bilgi için Fowler'ın makalesine bakın , ancak şimdilik bir sahte aşçıya odaklanalım.
-----------------------
| |
v |
mock cook <- waiter <- test driver
Garson bileşenini test eden ünitenin büyük bir kısmı, garsonun pişirme bileşeniyle nasıl etkileşime girdiğine odaklanır. Sahte bir yaklaşım, doğru etkileşimin ne olduğunu tam olarak belirlemeye ve ters gittiğinde algılamaya odaklanır.
Sahte nesne, test sırasında ne olması gerektiğini önceden bilir (örneğin, hangi yöntem çağrıları çağrılır, vb.) Ve sahte nesne, nasıl tepki vermesi gerektiğini bilir (örneğin, hangi dönüş değerinin sağlanması). Sahte, gerçekte olanın olması gerekenden farklı olup olmadığını gösterecektir. Bu test senaryosu için beklenen davranışı yürütmek üzere her test senaryosu için sıfırdan özel bir sahte nesne oluşturulabilir, ancak alaycı bir çerçeve, böyle bir davranış spesifikasyonunun doğrudan test senaryosunda açıkça ve kolayca gösterilmesine izin vermeye çalışır.
Sahte bir testi çevreleyen konuşma şöyle görünebilir:
Test sürücüsü için sahte aşçı : Bir hot dog sırasını beklemek ve cevap olarak ona bu kukla hot dog vermek
Test sürücüsü için (müşteri kılığında) garson : Ben bir sosisli istiyorum lütfen
garson için alay pişirmek : 1 sosis memnun
sahte aşçıyı için garson : 1 hot dog hazır (garsona kukla hot dog verir): yukarı sipariş
garson için test pilotu : İşte sosisli sandviç (sürücüyü test etmek için kukla sosis verir)test sürücüsü : TEST BAŞLADI!
Ama garsonumuz yeni olduğu için, olabilecek bu:
Test sürücüsü için sahte aşçı : Bir hot dog sırasını beklemek ve cevap olarak ona bu kukla hot dog vermek
Test sürücüsü için (müşteri kılığında) garson : Ben bir sosisli istiyorum lütfen
garson için pişirmek alay : 1 hamburger lütfen
sahte aşçı testi durdurur: Ben bir sosisli siparişi beklemek söylendi!test sürücüsü sorunu not ediyor: TEST BAŞARISIZ! - garson siparişi değiştirdi
veya
Test sürücüsü için sahte aşçı : Bir hot dog sırasını beklemek ve cevap olarak ona bu kukla hot dog vermek
Test sürücüsü için (müşteri kılığında) garson : Ben bir sosisli istiyorum lütfen
garson için alay pişirmek : 1 sosis memnun
sahte aşçıyı için garson : 1 hot dog hazır (garsona kukla hot dog verir): yukarı sipariş
garson için test pilotu : İşte patates kızartması (sürücüyü test etmek için başka bir siparişten patates kızartması verir)test sürücüsü beklenmedik patates kızartması not: TEST BAŞARISIZ! garson yanlış yemek geri verdi
Bununla gitmek için kontrast saplama tabanlı bir örnek olmadan sahte nesneler ve taslaklar arasındaki farkı açıkça görmek zor olabilir, ancak bu cevap zaten çok uzun :-)
Ayrıca bunun oldukça basit bir örnek olduğunu ve alaycı çerçevelerin, kapsamlı testleri desteklemek için bileşenlerden beklenen davranışların bazı oldukça sofistike özelliklerine izin verdiğini unutmayın. Daha fazla bilgi için sahte nesneler ve sahte çerçeveler üzerinde bol miktarda malzeme vardır.
Sahte Nesne, gerçek bir nesnenin yerine geçen bir nesnedir. Nesne yönelimli programlamada, sahte nesneler, gerçek nesnelerin davranışını kontrollü şekilde taklit eden simüle edilmiş nesnelerdir.
Bir bilgisayar programcısı, tipik olarak, bir otomobil tasarımcının, bir insanın araç çarpmalarındaki dinamik davranışını simüle etmek için bir çarpışma testi mankeni kullanması gibi, başka bir nesnenin davranışını test etmek için sahte bir nesne oluşturur.
http://en.wikipedia.org/wiki/Mock_object
Sahte nesneler, veritabanları gibi büyük, uygunsuz kaynakları taşımadan test senaryoları oluşturmanıza olanak tanır. Test için bir veritabanı çağırmak yerine, birim testlerinizde sahte bir nesne kullanarak veritabanınızı simüle edebilirsiniz. Bu, sizi sınıfınızdaki tek bir yöntemi test etmek için gerçek bir veritabanı kurma ve yırtma zorunluluğundan kurtarır.
"Mock" kelimesi bazen "Stub" ile dönüşümlü olarak kullanılmaktadır. İki kelime arasındaki farklar burada açıklanmaktadır. Temel olarak, bir sahte test edilen nesnenin / yöntemin uygun davranışı için beklentileri (yani "iddialar") içeren bir saplama nesnesidir.
Örneğin:
class OrderInteractionTester...
public void testOrderSendsMailIfUnfilled() {
Order order = new Order(TALISKER, 51);
Mock warehouse = mock(Warehouse.class);
Mock mailer = mock(MailService.class);
order.setMailer((MailService) mailer.proxy());
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")
.withAnyArguments()
.will(returnValue(false));
order.fill((Warehouse) warehouse.proxy());
}
}
warehouse
Ve mailer
sahte nesnelerin beklenen sonuçlarla programlandığına dikkat edin .
Sahte nesneler, gerçek olanların davranışlarını taklit eden simüle edilmiş nesnelerdir. Genellikle aşağıdaki durumlarda sahte bir nesne yazarsınız:
Mock nesnesi bir tür Test Double'dur . Test edilen sınıfın protokolünü / etkileşimini diğer sınıflarla test etmek ve doğrulamak için mockobjects kullanıyorsunuz.
Genellikle bir tür 'program' veya 'kayıt' beklentileri vardır: sınıfınızın temeldeki bir nesneye yapmasını beklediğiniz yöntem çağrıları.
Diyelim ki bir Widget'ta bir alanı güncellemek için bir hizmet yöntemini test ediyoruz. Ve mimarinizde veritabanıyla ilgilenen bir WidgetDAO var. Veritabanı ile konuşmak yavaş ve kurulum ve daha sonra temizlik karmaşık, bu yüzden Widgetdao alay edecek.
hizmetin ne yapması gerektiğini düşünelim: veritabanından bir Widget almalı, onunla bir şeyler yapmalı ve tekrar kaydetmelidir.
Bu yüzden sahte sahte bir kütüphaneye sahip sözde dilde şöyle bir şeyimiz olurdu:
Widget sampleWidget = new Widget();
WidgetDao mock = createMock(WidgetDao.class);
WidgetService svc = new WidgetService(mock);
// record expected calls on the dao
expect(mock.getById(id)).andReturn(sampleWidget);
expect(mock.save(sampleWidget);
// turn the dao in replay mode
replay(mock);
svc.updateWidgetPrice(id,newPrice);
verify(mock); // verify the expected calls were made
assertEquals(newPrice,sampleWidget.getPrice());
Bu şekilde diğer sınıflara bağlı sınıfların sürücü gelişimini kolayca test edebiliriz.
Martin Fowler tarafından alay edilen şeyleri ve saplamalardan nasıl farklı olduklarını açıklayan harika bir makale tavsiye ederim .
Bir bilgisayar programının bir kısmını test ederken, ideal olarak sadece o parçanın davranışını test etmek istersiniz.
Örneğin, bir şeyi yazdırmak için başka bir program kullanan bir programın hayali bir parçasından aşağıdaki sözde koda bakın:
If theUserIsFred then
Call Printer(HelloFred)
Else
Call Printer(YouAreNotFred)
End
Bunu test ediyorsanız, esas olarak kullanıcının Fred olup olmadığına bakan kısmı test etmek istersiniz. Gerçekten bir Printer
şeyleri test etmek istemiyorsunuz . Bu başka bir test olurdu.
Bu Mock nesneler Onlar şeylerin diğer tür taklit. Devreye giriyorsun. Bu durumda Printer
, gerçek bir yazıcı gibi davranması için bir Mock kullanırsınız , ancak yazdırma gibi rahatsız edici şeyler yapmazsınız.
Mock olmayan, kullanabileceğiniz birkaç başka taklit nesne türü vardır. Mocks'ı yapan en önemli şey, davranışlarla ve beklentilerle yapılandırılabilmeleridir.
Beklentiler , Mock'inizin yanlış kullanıldığında bir hata oluşturmasına izin verir. Yukarıdaki örnekte, Yazıcının "kullanıcı Fred'dir" test durumunda HelloFred ile çağrıldığından emin olmak isteyebilirsiniz. Bu olmazsa, Mock'ınız sizi uyarabilir.
Mocks'taki davranış, örneğin kodunuzun aşağıdaki gibi bir şey yaptığı anlamına gelir:
If Call Printer(HelloFred) Returned SaidHello Then
Do Something
End
Şimdi Yazıcı çağrıldığında ve SaidHello döndürdüğünde kodunuzun ne yaptığını test etmek istersiniz, böylece Mock'u HelloFred ile çağrıldığında SaidHello döndürecek şekilde ayarlayabilirsiniz.
Bu konuda iyi bir kaynak Martin Fowlers post Mocks Aren değil Stubs
Sahte ve saplama nesneleri, birim testinin önemli bir parçasıdır. Aslında , birim grupları yerine birimleri test ettiğinizden emin olmak için uzun bir yol kat ederler .
Özetle, bunu yapmak için başka nesneler ve mocks üzerinde Süt'ün (Sistem Altında Testi) bağımlılığını kırmak için taslakları kullanın ve SUT bağımlılık belirli yöntemler / özellikler olarak adlandırılır emin olun. Bu, birim testin temel ilkelerine geri döner - testlerin kolayca okunabilir, hızlı olması ve tüm gerçek sınıfların kullanılmasının gerektirebileceği bir yapılandırma gerektirmemesi gerekir.
Genel olarak, testinizde birden fazla saplama olabilir, ancak yalnızca bir alayınız olmalıdır. Bunun nedeni, alayın amacı davranışı doğrulamaktır ve testiniz yalnızca bir şeyi test etmelidir.
C # ve Adedi kullanarak basit senaryo:
public interface IInput {
object Read();
}
public interface IOutput {
void Write(object data);
}
class SUT {
IInput input;
IOutput output;
public SUT (IInput input, IOutput output) {
this.input = input;
this.output = output;
}
void ReadAndWrite() {
var data = input.Read();
output.Write(data);
}
}
[TestMethod]
public void ReadAndWriteShouldWriteSameObjectAsRead() {
//we want to verify that SUT writes to the output interface
//input is a stub, since we don't record any expectations
Mock<IInput> input = new Mock<IInput>();
//output is a mock, because we want to verify some behavior on it.
Mock<IOutput> output = new Mock<IOutput>();
var data = new object();
input.Setup(i=>i.Read()).Returns(data);
var sut = new SUT(input.Object, output.Object);
//calling verify on a mock object makes the object a mock, with respect to method being verified.
output.Verify(o=>o.Write(data));
}
Yukarıdaki örnekte taslakları ve alayları göstermek için Moq kullandım. Moq her ikisi için de aynı sınıfı kullanır - Mock<T>
bu biraz kafa karıştırıcı hale getirir. Ne olursa olsun, çalışma zamanında, eğer output.Write
verilerle çağrılmazsa test başarısız parameter
olurken, arama input.Read()
başarısızlığı başarısız olmaz.
Başka bir cevabın önerdiği gibi " Alay Değil Saplamalar " , alaylar gerçek bir nesne yerine kullanılacak bir "test double" biçimidir. Bunları saplama nesneleri gibi diğer test çiftlerinden farklı kılan şey, diğer test çiftlerinin durum doğrulaması (ve isteğe bağlı olarak simülasyon) sunması, taklitçiler ise davranış doğrulaması (ve isteğe bağlı olarak simülasyon) sunmasıdır.
Bir saplama ile, saplama üzerinde çeşitli yöntemleri herhangi bir sırayla (hatta tekrarlı olarak) çağırabilir ve saplamanın istediğiniz bir değeri veya durumu yakalayıp yakalamadığını başarılı bir şekilde belirleyebilirsiniz. Buna karşılık, bir sahte nesne belirli bir sırayla ve hatta belirli sayıda çağrılacak çok özel işlevler beklenir. Bir sahte nesne ile yapılan test, "yöntemler" farklı bir sırayla veya sayımla çağrıldığından "başarısız" olarak değerlendirilecektir - sahte nesne, test sona erdiğinde doğru duruma sahip olsa bile!
Bu şekilde, sahte nesneler genellikle saplama nesnelerinden daha SUT koduna daha sıkı bağlı olarak kabul edilir. Neyi doğrulamaya çalıştığınıza bağlı olarak bu iyi veya kötü bir şey olabilir.
Sahte nesneler kullanma noktasının bir kısmı, spesifikasyonlara göre gerçekten uygulanması gerekmemesidir. Sadece kukla cevaplar verebilirler. Örneğin, A ve B bileşenlerini uygulamanız gerekiyorsa ve her ikisi de birbirini "çağırıyorsa" (etkileşime giriyorsa), B uygulanana kadar A'yı test edemezsiniz; Test odaklı geliştirmede bu bir sorundur. Eğer ( "kukla") sahte oluşturmak Yani çok basit olduğunu, A ve B için nesneleri, ancak verdikleri bazı onlar ile etkileşim yaparken yanıtın tür. Bu şekilde A'yı B için sahte bir nesne kullanarak uygulayabilir ve test edebilirsiniz.
Php ve phpunit için phpunit belgesel iyi açıklanmıştır. Burada bkz PHPUnit belgeleri
Basit kelime alay nesnesi sadece orijinal nesnenin kukla nesnesidir ve dönüş değerini döndürür, bu dönüş değeri test sınıfında kullanılabilir
Birim testlerin ana perspektiflerinden biridir. evet, tek bir kod biriminizi test etmeye çalışıyorsunuz ve test sonuçlarınız diğer fasulye veya nesnelerin davranışlarıyla alakalı olmamalıdır. bu yüzden bazı basitleştirilmiş karşılıklı yanıtlarla Mock nesnelerini kullanarak onları alay etmelisiniz.