Mockito ile geçersiz yöntemler nasıl atılır


938

Geçersiz dönüş tipi ile yöntemler nasıl takılır?

Bir gözlemci modeli uyguladım ama Mockito ile alay edemem çünkü nasıl olduğunu bilmiyorum.

İnternette bir örnek bulmaya çalıştım ama başarılı olamadım.

Sınıfım şöyle:

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal,Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private string state;
    //setter getter state
} 

public class WorldTest implements Listener {

    @Test public void word{
    World  w= mock(World.class);
    w.addListener(this);
    ...
    ...

    }
}

interface Listener {
    void doAction();
}

Sistem sahte ile tetiklenmez.

Yukarıda belirtilen sistem durumunu göstermek istiyorum. Ve onlara göre iddialarda bulunun.


6
Sahte yöntemlerin geçersiz yöntemlerin varsayılan olarak hiçbir şey yapmadığını unutmayın!
Hat

1
@ Çizgi, aradığım şey buydu. Söyledikten sonra açık görünüyor. Ancak bir alay ilkesini vurgulamaktadır: Sadece alay edilen sınıfların yöntemlerini, etkileri için (bir dönüş değeri veya bir istisna gibi) alay etmelisiniz. Teşekkür ederim!
allenjom

Yanıtlar:


1145

Mockito API belgelerine bir göz atın . Bağlantılı belge (Nokta # 12) bahseder gibi size herhangi birini kullanabilirsiniz doThrow(), doAnswer(), doNothing(), doReturn()mockito çerçevesinden yöntemlerin aile geçersiz yöntemleri alay.

Örneğin,

Mockito.doThrow(new Exception()).when(instance).methodName();

veya bunu takip davranışıyla birleştirmek istiyorsanız,

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

setState(String s)Aşağıdaki Dünya sınıfında ayarlayıcı alaycı baktığınızı varsayarsak , kod doAnsweralay etmek için yöntem kullanır setState.

World  mockWorld = mock(World.class); 
doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      System.out.println("called with arguments: " + Arrays.toString(args));
      return null;
    }
}).when(mockWorld).setState(anyString());

8
@ qualidafial: Evet, dönüş türüyle ilgilenmediğimi daha iyi ifade ettiği için Void'e parametreleştirmenin daha iyi olacağını düşünüyorum. Bu yapının farkında değildim, işaret ettiğiniz için teşekkürler.
sateesh

2
doThrow şimdi # 5 (ayrıca benim için doThrow'u kullanıyorum, bu "takipçiye izin verilmiyor" mesajı izledi, takipçiler için ...)
rogerdpack

@ qualidafial: Bence Answer.answer çağrısının dönüş türü orijinal yönteme döndürülen şey değildir, muhtemelen testinizde bu değerle başka bir şey yapmak istiyorsanız doAnswer çağrısına döndürülen şeydir.
twelve17

1
:( guava doNothing () .'de RateLimiter.java sürüm 16.0.1'in Mock'unu denemeye çalışırken. bu yüzden setRate yöntemimi alay etmedi :( ama bunun yerine çağırdı :(
Dean Hiller

2
@DeanHiller ihbar setRate()olduğu finalbu nedenle ve alay edilemez. Bunun yerine create()ihtiyacınız olanı yapan bir örneği deneyin . Alay etmeye gerek yok RateLimiter.
dimo414

113

Sanırım bu soruya daha basit bir cevap buldum, sadece tek bir yöntem için gerçek yöntemi çağırmak (boş bir dönüş olsa bile) bunu yapabilirsiniz:

Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();

Ya da, bu sınıfın tüm yöntemleri için gerçek yöntemi çağırarak şunları yapabilirsiniz:

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);

13
Buradaki gerçek cevap bu. Spy () yöntemi iyi çalışır, ancak genellikle nesnenin her şeyi normal şekilde yapmasını istediğinizde ayrılır.
biggusjimmus

1
Ne anlama geliyor? Aslında yöntemleri mi arıyorsun? Daha önce mockito kullanmamıştım.
obesechicken13

Evet, sahte gerçek yöntemleri çağıracak. @Mock'u kullanıyorsanız, aynı sonuçları elde etmek için aşağıdakileri kullanabilirsiniz: @Mock (answer = Yanıtlar.CALLS_REAL_METHODS).
Ale

70

@Sateesh'in söylediklerine ek olarak, testin çağrılmasını önlemek için geçersiz bir yöntemle alay etmek istediğinizde, şu şekilde kullanabilirsiniz Spy:

World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();

Testinizi çalıştırmak istediğinizde, test edilen yöntemi spynesnede değil , nesnede çağırdığınızdan emin olun world. Örneğin:

assertEquals(0,spy.methodToTestThatShouldReturnZero());

57

Sözde sorunun çözümü kullanmaktır spy Mockito.spy (...) yerine mock Mockito.mock (..) .

Casus kısmi alay etmemizi sağlar. Mockito bu konuda iyidir. Çünkü tam olmayan bir sınıfınız var, bu şekilde bu sınıfta gerekli olan bazı yerlerle alay ediyorsunuz.


3
Burada tökezledim çünkü benzer bir sorunum vardı (tesadüfen bir Konu / Gözlemci etkileşimini test ediyordu). Ben zaten bir casus kullanıyorum ama farklı bir şey yapmak için 'SubjectChanged' yöntemi istiyorum. Sadece yöntemin çağrıldığını görmek için `verify (observer) .subjectChanged (Subject) kullanabilirsiniz. Ancak, bir nedenden dolayı, yöntemi geçersiz kılmayı tercih ederim. Bunun için Sateesh'in yaklaşımı ve burada cevabınız bir arada ...
gMale

32
Hayır, bunu yapmak aslında geçersiz yöntemlerle alay etmenize yardımcı olmaz. Hile, sateesh'in cevabında listelenen dört Mockito statik yönteminden birini kullanmaktır.
Dawood ibn Kareem

2
@Sorunuzdaki sorularınız için aşağıdaki stackoverflow.com/questions/1087339/… adresine bakın .
ibrahimyilmaz

Bu doz aslında işe yarıyor.
Nilotpal

34

Her şeyden önce: her zaman mockito static'i içe aktarmalısınız, bu şekilde kod çok daha okunabilir (ve sezgisel) olacaktır:

import static org.mockito.Mockito.*;

Kısmi alay ve hala orijinal işlevselliği korumak için mockito "Casus" sunuyor.

Aşağıdaki gibi kullanabilirsiniz:

private World world = spy(World.class);

Bir yöntemin yürütülmesini önlemek için şöyle bir şey kullanabilirsiniz:

doNothing().when(someObject).someMethod(anyObject());

bir yönteme bazı özel davranışlar vermek için "thenReturn" ile "when" kullanın:

doReturn("something").when(this.world).someMethod(anyObject());

Daha fazla örnek için lütfen doc'deki mükemmel mockito örneklerini bulun.


4
Statik içe aktarmanın onu daha okunabilir hale getirmekle ne ilgisi var?
jsonbourne

2
kelimenin tam anlamıyla hiçbir şey.
specializt

2
Bence bu bir zevk meselesi, sadece ifade (neredeyse) bir ingilizce cümle gibi görünmesini istiyorum ve Class.methodname (). Bir şey () vs. methodname () .something daha az akıcı okunabilir.
fl0w

1
Bir takım üzerinde çalışıyorsanız, içe aktarma statik, içe aktarmada genellikle bir joker karakter bulunduğundan, başkalarının yöntemin nereden geldiğini görmesi için kıçından acı çeker.
LowKeyEnergy

bu doğru, ancak Test kodu ve Mockito için bu açık olmalı ve sorun değil.
fl0w

27

Mockito ile geçersiz yöntemler nasıl atılır - iki seçenek vardır:

  1. doAnswer - Eğer alaycı boşluk yöntemimizin bir şey yapmasını istiyorsak (geçersiz olmasına rağmen davranışı alay et).
  2. doThrow- O zaman Mockito.doThrow()alaycı void yönteminden bir istisna atmak istiyorsanız.

Aşağıda bunun nasıl kullanılacağına dair bir örnek verilmiştir (ideal bir kullanıcı tabanı değil, sadece temel kullanımı göstermek istedim).

@Test
public void testUpdate() {

    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] arguments = invocation.getArguments();
            if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {

                Customer customer = (Customer) arguments[0];
                String email = (String) arguments[1];
                customer.setEmail(email);

            }
            return null;
        }
    }).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

    //some asserts
    assertThat(customer, is(notNullValue()));
    assertThat(customer.getEmail(), is(equalTo("new@test.com")));

}

@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {

    doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("old@test.com", "new@test.com");

}
}

Sen nasıl daha fazla ayrıntı bulabildiğim alay ve sınamak geçersiz benim sonrası Mockito ile yöntemlerini Mockito (örneklerle kapsamlı bir rehber) ile alay nasıl


1
Harika bir örnek. Not: Java 8'de, anonim bir sınıf yerine lambda kullanmak biraz daha hoş olabilir: 'doAnswer ((Cevap <Void>) çağırma -> {// CODE}). When (mockInstance) .add (yöntem ());
miwe

16

Gruplara bir cevap daha ekliyoruz (cinas yok) ...

Casus kullanmak istemiyorsanız doAnswer yöntemini çağırmanız gerekir. Ancak, mutlaka kendi rulo gerekmez Cevap . Birkaç varsayılan uygulama vardır. Özellikle, CallsRealMethods .

Uygulamada, şuna benzer:

doAnswer(new CallsRealMethods()).when(mock)
        .voidMethod(any(SomeParamClass.class));

Veya:

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
        .voidMethod(any(SomeParamClass.class));

16

Java 8'de, aşağıdakiler için statik bir içe aktarma yaptığınız varsayılarak, biraz daha temiz yapılabilir org.mockito.Mockito.doAnswer:

doAnswer(i -> {
  // Do stuff with i.getArguments() here
  return null;
}).when(*mock*).*method*(*methodArguments*);

Bu return null;önemlidir ve bu olmadan derleme, uygun bir geçersiz kılma bulamayacağından oldukça belirsiz bazı hatalarla başarısız olur doAnswer.

Örneğin ExecutorService, Runnableiletilen herhangi bir işlemi hemen gerçekleştiren bir aşağıdakiler execute()kullanılarak uygulanabilir:

doAnswer(i -> {
  ((Runnable) i.getArguments()[0]).run();
  return null;
}).when(executor).execute(any());

2
Bir satırda: Mockito.doAnswer ((i) -> null) .when (örnek) .method (any ());
Akshay Thorve

@AkshayThorve Aslında i ile bir şeyler yapmak istediğinizde işe yaramaz.
Tim B

7

Bence problemlerin test yapısından kaynaklanıyor. Alaycılığı, test sınıfındaki arayüzleri uygulamak için geleneksel yöntemle karıştırmayı zor buldum (burada yaptığınız gibi).

Dinleyiciyi bir Mock olarak uygularsanız etkileşimi doğrulayabilirsiniz.

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

Bu sizi 'Dünya'nın doğru şeyi yaptığını tatmin etmelidir.


0

Mockito.doThrow'u şu şekilde kullanarak:

Mockito.doThrow(new Exception()).when(instance).methodName();

bu güzel örneği deneyebilirsiniz:

public void testCloseStreamOnException() throws Exception {
    OutputStream outputStream = Mockito.mock(OutputStream.class);
    IFileOutputStream ifos = new IFileOutputStream(outputStream);
    Mockito.doThrow(new IOException("Dummy Exception")).when(outputStream).flush();
    try {
      ifos.close();
      fail("IOException is not thrown");
    } catch (IOException ioe) {
      assertEquals("Dummy Exception", ioe.getMessage());
    }
    Mockito.verify(outputStream).close();
  }

Kaynak: http://apisonar.com/java-examples/org.mockito.Mockito.doThrow.html#Example-19

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.