2014-08-28 16 views
5

Si supponga che voglio testare il codice come questo:Ottenere numero di chiamate ad un mock

class ClassToTest 
    // UsedClass1 contains a method UsedClass2 thisMethod() {} 
    UsedClass1 foo; 
    void aMethod() 
    { 
    int max = new Random().nextInt(100); 
    for(i = 0; i < max; i++) 
    { 
     foo.thisMethod().thatMethod(); 
    } 
    } 
} 

Se ho un test come questo:

ClassToTest test; 
UsedClass1 uc1; 
UsedClass2 uc2; 
@Test 
public void thingToTest() { 
    test = new ClassToTest(); 
    uc1 = mock(UsedClass1.class); 
    uc2 = mock(UsedClass2.class); 
    when(uc1.thisMethod()).thenReturn(uc2); 
    when(uc2.thatMethod()).thenReturn(true); 

    test.aMethod(); 

    // I would like to do this 
    verifyEquals(callsTo(uc1.thisMethod()), callsTo(uc2.thatMethod())); 
} 

Come posso ottenere il numero di chiamate al uc1.thisMethod() e uc2.thatMethod() così posso verificare che entrambi sono stati chiamati lo stesso numero di volte?

+1

L'unico modo in cui posso pensare (al momento) è posizionare un wrapper attorno a ciascun metodo, che incrementa wn contrastano ogni volta che viene chiamato. AFAIK il jvm non tiene traccia del numero di volte in cui un metodo/classe viene chiamato/istanziato. – munyul

risposta

1

È possibile utilizzare un VerificationMode personalizzato per contare le invocazioni, qui si va:

public class InvocationCounter { 

    public static <T> T countInvocations(T mock, AtomicInteger count) { 
     return Mockito.verify(mock, new Counter(count)); 
    } 

    private InvocationCounter(){} 

    private static class Counter implements VerificationInOrderMode, VerificationMode { 
     private final AtomicInteger count; 

     private Counter(AtomicInteger count) { 
      this.count = count; 
     } 

     public void verify(VerificationData data) { 
      count.set(data.getAllInvocations().size()); 
     } 

     public void verifyInOrder(VerificationDataInOrder data) { 
      count.set(data.getAllInvocations().size()); 
     } 

     @Override 
     public VerificationMode description(String description) { 
      return VerificationModeFactory.description(this, description); 
     } 

    } 

} 

E poi usare in questo modo (funziona anche con tipi di ritorno void):

@Mock 
private Function<String, Integer> callable; 

AtomicInteger count= new AtomicInteger(); //here is the actual invocation count stored 

countInvocations(callable,count).apply(anyString()); 

assertThat(count.get(),is(2)); 
+0

Sfortunatamente, per qualche ragione questo approccio non ha funzionato per me. Semplicemente non stava aggiornando i contatori. Quindi, ho usato l'approccio menzionato nella risposta da @antoniob - con _doAnswer (...) _ - e ha funzionato. –

6

Si potrebbe stub i vostri metodi, e incrementare un contatore, come questo:

final AtomicInteger countCall1 = new AtomicInteger(); 

Mockito.doAnswer(new Answer<UsedClass2>() { 
    @Override 
    public UsedClass2 answer(InvocationOnMock invocation) throws Throwable { 
     countCall1.incrementAndGet(); 
     return uc2; 
    } 
}).when(uc1).thisMethod(); 
+0

Fuori interesse, perché il 'AtomicInteger'? –

+1

Per rendere il metodo thread-safe. Se thisMethod viene chiamato da diversi thread, AtomicInteger consente di incrementare il contatore in modo sicuro. – antoniob

+0

Ok, ho pensato che fosse la tua ragione, ma ho pensato di controllare (soprattutto dal momento che il codice di esempio non includeva più thread). –

2

Se si conosce il numero di volte in cui un metodo viene suppoed essere chiamato è possibile utilizzare il metodo times() di Mockito

//for example if had to be called 3 times 
verify(uc1, times(3)).thisMethod(); 
verify(uc2, times(3)).thatMethod(); 

Tuttavia, ora vedo che si chiama il metodo un numero casuale di volte, quindi questa probabilmente non è la risposta migliore a meno che non si estenda il generatore di numeri casuali per restituire sempre un valore previsto.

+0

Il numero casuale era solo un esempio - dal momento che abbiamo già il numero di chiamate disponibili indirettamente tramite il metodo 'times()', sembra strano che non ci sia modo di accedere direttamente a quel conteggio. –

10

Puoi fare qualcosa del genere:

YourService serviceMock = Mockito.mock(YourService.class); 

// code using YourService 

// details of all invocations including methods and arguments 
Collection<Invocation> invocations = Mockito.mockingDetails(serviceMock).getInvocations(); 
// just a number of calls of any mock's methods 
int numberOfCalls = invocations.size(); 
Problemi correlati