Sahte nesnelerin amacı nedir?


167

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?


12
Bunlar, eldeki sorun için ihtiyaç duymadığınız esneklikle şeyleri kitlesel olarak yapılandırmak için bir araçtır.
dsimcha

2
olası yinelenen Ne alaycı nedir?
nawfal

Yanıtlar:


363

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.

Birim Testi

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 .

Sahte Nesneler

Şimdi, test aşçısı (test double) farklı şekillerde uygulanabilir:

  • sahte bir aşçı - dondurulmuş akşam yemekleri ve bir mikrodalga kullanarak aşçı gibi davranan biri,
  • bir saplama aşçı - ne sipariş verirseniz verin her zaman sosisli sandviç veren bir sosisli satıcı veya
  • sahte bir aşçı - sokma işleminde bir aşçı gibi davranan bir senaryoyu takip eden gizli bir polis.

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.


12
Bu harika bir açıklama, ancak bir dereceye kadar garsonun uygulanmasını test etmiyor musunuz? Sizin durumunuzda, muhtemelen doğru API'yi kullandığınızdan emin olduğunuz için sorun değil, ancak bunu yapmanın farklı yolları varsa ve garson birini veya diğerini seçebilir mi? Birim testinin amacının uygulamayı değil API'yi test etmek olduğunu düşündüm. (Bu her zaman kendimi alaycılığı okurken sorduğum bir soru.)
davidtbernal

8
Teşekkürler. Garson için spec görmeden (veya tanımlamak) "uygulama" test olup olmadığını söyleyemeyiz. Garsonun yemeğin kendisini pişirmesine veya siparişi caddeden aşağıya doldurmasına izin verildiğini varsayabilirsiniz, ancak garson için spesifikasyonun hedeflenen şefi kullanmayı içerdiğini varsayarsınız - sonuçta, üretim şefi pahalı, gurme bir şef ve biz ' d garsonumuzun onu kullanmasını tercih ederim. O spec olmadan, ben haklısın sonuçlandırmak zorundayım sanırım - garson ancak "doğru" olması için istediği sipariş doldurabilirsiniz. OTOH, bir spec olmadan, test anlamsız. [Devamı ...]
Bert F

8
HİÇBİR ZAMAN, beyaz kutu vs kara kutu birim testi fantastik konuya yol büyük bir noktaya. Ünite testinin beyaz kutu yerine kara kutu olması gerektiğini söyleyen bir endüstri konsensüsü olduğunu düşünmüyorum ("API'yi test edin, uygulamayı değil"). En iyi birim testinin, test kırılganlığını kod kapsamı ve test senaryosu tamlığına karşı dengelemek için muhtemelen ikisinin bir kombinasyonu olması gerektiğini düşünüyorum.
Bert F

1
Bu cevap bana göre yeterince teknik değil. Gerçek nesneleri kullanabildiğimde neden sahte nesne kullanmam gerektiğini bilmek istiyorum.
Niklas R.

1
Büyük açıklama !! Teşekkür ederim!! @BertF
Bharath Murali

28

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());
  }
}

warehouseVe mailersahte nesnelerin beklenen sonuçlarla programlandığına dikkat edin .


2
Verdiğiniz tanım "saplama nesnesi" nden en az farklı değildir ve bu nedenle sahte bir nesnenin ne olduğunu açıklamaz.
Brent Arias

Başka düzeltme "kelime 'Sahte' bazen yanlışlıkla 'saplama' ile birbirlerinin yerine kullanılır".
Brent Arias

@Myst: İki kelimenin kullanımı evrensel değildir; yazarlar arasında farklılık gösterir. Fowler bunu söylüyor ve Wikipedia makalesi bunu söylüyor. Bununla birlikte, değişiklikte düzenleme yapmaktan ve indirgenizi kaldırmaktan çekinmeyin. :)
Robert Harvey

1
Robert ile aynı fikirdeyim: "alay" kelimesinin kullanımı endüstri genelinde değişiklik gösterme eğilimindedir, ancak deneyimlerime göre belirlenmiş bir tanım yoktur , ancak test edilen gerçek nesne DEĞİLDİR, bunun yerine gerçek nesne veya tüm parçaları çok rahatsız edici ve çok az sonucu olacaktır.
mkelley33

15

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:

  • Gerçek nesne, bir birim testine dahil edilemeyecek kadar karmaşıktır (Örneğin, bir ağ iletişimi, diğer eş olanı taklit eden bir sahte nesneye sahip olabilirsiniz)
  • Nesnenizin sonucu belirleyici değil
  • Gerçek nesne henüz mevcut değil

12

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.



9

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


7

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.Writeverilerle çağrılmazsa test başarısız parameterolurken, arama input.Read()başarısızlığı başarısız olmaz.


4

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.


3

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.


1

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


0

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.

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.