2011-12-04 10 views
5

Bozuk olmadıklarından emin olmak için karakterlerin hangi sırada olduğunu doğrulamak istiyorum. InOrder kullanarak yazmayı denedim ama işe yaramıyor gibi görünüyor, ya da en azından Mockito 1.8.5.Mockito'da aynı argümanlarla belirli bir arama sırası için nasıl test edilir?

@Test 
public void inOrderTest() throws IOException{ 
    final String message = "Hello World!\n"; 

    for(char c : message.toCharArray()) 
     mockWriter.write(c); 

    final InOrder inOrder = inOrder(mockWriter); 
    for(char c : message.toCharArray()) 
     inOrder.verify(mockWriter).write(c); 
    inOrder.verifyNoMoreInteractions(); 
} 

testi yukarıdaki iletisiyle başarısız olur:

Verification in order failure: 
mockWriter.write(108); 
Wanted 1 time: 
-> at  org.bitbucket.artbugorski.brainfuj.interpreter.InterpreterTest.inOrderTest(InterpreterTest.java:62) 
But was 3 times. Undesired invocation: 
-> at org.bitbucket.artbugorski.brainfuj.interpreter.InterpreterTest.inOrderTest(InterpreterTest.java:58) 

İnsan nasıl bunun için bir mockito testi yazar?


DÜZENLEME: Eğer 'l' olsun ve Mockito söyleyince sırayla http://code.google.com/p/mockito/issues/detail?id=296

cevap

19

Daha önce yanıt verenler için özür dilerim; ama bence, bir Cevap kullanmak, Mockito'nun temel fikirlerinden biri karşısında biraz uçuyor, yani, saplama ve doğrulama, tamamen iki ayrı süreçtir. Mockito, doğrulama için özellikler ve doğrulama için özelliklere sahiptir ve Mockito'nun yapımcıları, ikisini ayrı tutmak için çaba sarf etmişlerdir. Cevaplar stubbing için tasarlanmıştır; Ve bir Cevabın doğrulamanın en iyi yolu olduğu birkaç durum söz konusu ise de, bunun onlardan biri olduğuna inanmıyorum.

Bir Yanıt yerine bir ArgumentCaptor kullanırım. Test sınıfında böyle bir yöntem yazabilirim, sonra argüman olarak "Merhaba dünya" olarak adlandırırdım. Bunu test etmediğimi, bu nedenle yazım hataları içerebileceğini unutmayın.

private void verifyCharactersWritten(String expected){ 
    ArgumentCaptor<Character> captor = ArgumentCaptor.forClass(Character.class); 
    verify(mockWriter, times(expected.length())).write(captor.capture()); 
    assertEquals(Arrays.asList(expected.toCharArray()), captor.getAllValues()); 
} 

Bu yardımcı olur umarım.

+0

Slick. Arg kapıcının bu özelliğini bilmiyordum. –

+0

bazen sonucu/çıktı/sonucu kontrol etmek için (eğer mümkünse) bu test kodunu okuyun. Demek istediğimiz, eğer bize geri dönmesi gerektiğini bilseydik: "muhtemel argümanlar için" beklediğimiz bazı sokmalar ". – ses

4

Doğrulama hata olarak Filed yapılır kaç kez bir şey ayrı bir kavramdır, bu yüzden doğrulamak için oldu, siparişin kontrolünden geçiyor, ama başarısız oluyor çünkü 'l' çağrısı üç kez yapıldı ve siz (örtülü olarak) sadece bir kez beklemesini söylediniz. Mockito'da daha önce vurduğum bir tuhaflık, ama ne zaman olursa olsun, testimin kötü bir şekilde yazıldığına karar veriyorum ve düzeltdiğimde sorun ortadan kalkıyor. Sizin durumunuzda, bir Yazara yazılan her karakteri doğrulamak için overkill olduğunu söyleyebilirim. Bir mesajı doğru bir şekilde doğrulamak istiyorsanız, giriş mesajını çıkış mesajıyla karşılaştırmalısınız. Örneğinizde, bu bir yazarla alay etmek yerine StringWriter kullanmak isteyebilir. Gerçekten ne yaptığını yapmak zorunda kalırsam Sonra testin sonunda sadece

assertThat(stringWriter.toString(), equalTo(message)); 

benziyor, ben önerebilirsiniz tüm gerçekleşmesi ve muhtemelen yapmak için bir yol olup olmadığını görmek için mockito koduna kazma olduğunu Bu konuda ne dediklerini görmek için bir hata raporu doldurmak.

+0

Ben I böylece bir sanal makine/tercüman yazıyorum/O bir karakter de olur

Unitils Mock ile Bir zaman, tüm bir mesajın nosyonu yoktur, sadece bir dizi tekil karakter stdout'a basılır. Ben onları baskıya uğratma konusunda hiçbir şeyi bozmamaya çalışıyorum (evet, kendi iç belleğimi yapıyorum). Doğrulamaya çalıştığım mesaj "Merhaba Dünya" dır, bu yüzden böyle bir mesajın karakterle karakter olarak doğru bir şekilde basılabileceğini test etmenin aşırı zor olduğunu düşünmüyorum. :) – ArtB

+1

Merhaba, eğer bu test kritikse, yani ne emittiğinizi test etmelisiniz, @Ryan ile aynı fikirdeyim, girişin çıkış ile karşılaştırmasını tercih etmelisiniz. Yazıcınızı koyduktan sonra, her zamanki bir 'StringBuilder'de char'i ekleyecek, ardından 'Hello World'' girdimizle karşılaştıracak özel bir cevap kullanın. Alternatif olarak, muhtemelen özel bir eşleştirici yazabilirsiniz; inOrder.verify (mockWriter, times (11)) gibi bir şey yazabilirsiniz. (charsThatMatchInOrder ("Hello World")); ', ** ancak bu dize değiştiğinde bu kopuş kolayca kırılabilir! ** – Brice

+0

@Sadece kod snippet'i Öykünme/yorumlama test girişinin bir parçası olduğundan, evet eğer test değişirse testin başarısız olması beklenir. – ArtB

0

Şu anda özel bir Yanıtla bu konu hakkında hack alıyorum.

final List<Integer> writtenChars = new ArrayList<>(); 
willAnswer(
     new Answer(){ 
      @Override 
      public Object answer(final InvocationOnMock invocation)throws Throwable { 
       final int arg = (int) invocation.getArguments()[0]; 
       writtenChars.add(arg); 
       return null; 
      } 
     } 
    ).given(mockWriter).write(anyInt()); 

Ardından, istediğiniz yöntemleri yürüttükten sonra, beklenen String'e karşı listeye karşı test ediyorum. Brice size özür: Bu olsa

final Iterator<Integer> writtenCharItr = writtenChars.iterator(); 
for(int charInt : "Hello World!\n".toCharArray()) 
    assertThat( charInt, is(writtenCharItr.next()) ); 
assertThat("There are no more chars.", writtenCharItr.hasNext(), is(false)); 
verify(mockWriter).flush(); 

vb


DÜZENLEME yöntemi denir var listede kayıt sürece yöntem çağrısı kereden fazla ilgileniyorsanız çalışmaz Bir liste daha iyi çalışıyor olsa da, bağımsız olarak ve daha iyi List yerine bir StringBuilder kullanarak bağımsız ve daha iyi bu çözüm gelmek gibi görünüyor.

+0

Ne düşünüyordum ... Bir ArgumentCaptor çok daha iyi, temel olarak bu özel yanıtın ne yaptığını yapıyor. David'in cevabı birçok yönden çok daha doğru. – Brice

2

Mockito'nun bu şekilde çalışmasının nedeni, doğrulama ve düzenli doğrulama arasındaki tutarlılıktır. Diğer bir deyişle, eğer bu yolu uygulamamış olsaydık, API farklı bir şekilde şaşırtıcı olurdu :) Size iyi bir api tasarlamaya çalışırken yapılan trade off'lar.

Yani ... cevap. İlk olarak, test kodundaki döngüler (veya koşullu) gibi ifadelerden kaçınmalısınız. Bunun nedeni, test kodu netliği ve sürekliliği için çok önemlidir! =)

Döngüleri testten çıkarırsak, artık bir kullanım durumumuz kalmaz, ... Kullanım durumu olmadan cevap vermek zordur. David'in ArgumentCaptor'ı kötü bir fikir olmayabilir.

Bu yardımcı olur umarım!

+0

Katılmıyorum. Döngüyü açabilirdim ve aynı sorunu yaşayabilirdim. Bunu hata ayıklamaya çalışırken yaptığım gibi bir gerçeği biliyorum. İkincisi, eğer Ingelder'i çağırıyorsa, ancak çağrıların hangi sırayla yapıldığını tam olarak söyleyemem, en az şaşkınlık ilkesinin göz kamaştırıcı bir ihlali değil midir? – ArtB

0

Bu garip bir testtir, ancak yine de alay API'sı tarafından desteklenmelidir. Diğer alay API'ları desteklediğinden, 'un'un Mockito tarafından desteklenebileceğine inanıyorum.

Mock<Writer> mockWriter; 

@Test 
public void inOrderTest() throws Exception { 
    Writer writer = mockWriter.getMock(); 
    final String message = "Hello World!\n"; 

    for (char c : message.toCharArray()) 
     writer.write(c); 

    for (char c : message.toUpperCase().toCharArray()) 
     mockWriter.assertInvokedInSequence().write(c); 
    MockUnitils.assertNoMoreInvocations(); 
} 

Ya JMockit (kendi aracı) ile:

@Test 
public void inOrderTest(final Writer mockWriter) throws Exception { 
    final String message = "Hello World!\n"; 

    for (char c : message.toCharArray()) 
     mockWriter.write(c); 

    new FullVerificationsInOrder() {{ 
     for (char c : message.toCharArray()) 
      mockWriter.write(c); 
    }}; 
} 
İlgili konular