2014-06-18 4 views
7

Ho un problema quando provo ad abbinare un array che viene passato come parametro a un metodo che riceve un array varargs.c'è Mockito eq matcher per varargs array?

Il matcher anyVararg() menzionato in altre domande/risposte non funziona per me perché voglio essere sicuro che l'array fornito sia quello di cui ho bisogno.

ho ridotto il problema a questo esempio che è più facile da capire e astrae il problema (il mio vero problema è il codice di produzione e ha logica busines quindi sarebbe fonte di confusione per lo scopo di questa domanda):

@RunWith(MockitoJUnitRunner.class) 
public class UnitTest { 
    private Object[] objectArray; 
    private List<Object> expected; 
    private TestTarget target; 

    @Before 
    public void setUp() { 
     objectArray = new Object[]{ new Object() }; 
     expected = Arrays.asList(new Object(), new Object()); 
     target = Mockito.spy(new TestTarget()); 
    } 

    @Test 
    public void testMakeList() { // this pass as eq works well with normal array 
     doReturn(expected).when(target).toList(Mockito.eq(objectArray)); 
     Assert.assertEquals(expected, target.makeList(objectArray)); 
    } 

    @Test 
    public void testMakeList1() { // this one fails as eq is not working with varargs 
     doReturn(expected).when(target).toList1(Mockito.eq(objectArray)); 
     Assert.assertEquals(expected, target.makeList1(objectArray)); 
    } 

    @Test 
    public void testMakeListWithAryEq() { // fails, aryEq is not working with varargs 
     doReturn(expected).when(target).toList1(AdditionalMatchers.aryEq(objectArray)); 
     Assert.assertEquals(expected, target.makeList1(objectArray)); 
    } 

    private class TestTarget { 
     public List<Object> makeList(Object[] objects) { 
      return toList(objects); 
     } 

     public List<Object> makeList1(Object[] objects) { 
      return toList1(objects); 
     } 

     protected List<Object> toList(Object[] objs) { 
      return null; // Not implemented "Intentionally" 
     } 

     protected List<Object> toList1(Object... objs) { 
      return null; // Not implemented "Intentionally" 
     } 
    } 
} 

Quando eseguo i test case nella classe, il primo test case passerà ma non gli altri due, né usando eq né usando aryEq. Mostrando la seguente traccia:

java.lang.AssertionError: expected:<[[email protected], [email protected]384a]> but was:<null> 
    at org.junit.Assert.fail(Assert.java:88) 
    at org.junit.Assert.failNotEquals(Assert.java:743) 
    at org.junit.Assert.assertEquals(Assert.java:118) 
    at org.junit.Assert.assertEquals(Assert.java:144) 
    ... 

Ciò accade perché il matcher eq non funziona con varargs array, c'è qualche alternativa al matcher eq per questo caso d'uso?

risposta

6

Ok, penso che la risposta qui richiede un matcher su misura, che può essere implementato nella vostra unit test come così:

private class MyVarargMatcher extends ArgumentMatcher<Object[]> implements VarargMatcher { 
    private Object[] expectedValues; 

    MyVarargMatcher(Object... expectedValues) { 
     this.expectedValues = expectedValues; 
    } 

    @Override 
    public boolean matches(Object varargArgument) { 
     return new EqualsBuilder() 
     .append(expectedValues, varargArgument) 
     .isEquals(); 
    } 
} 

Poi, nel testMakeList1() cambiare la prima linea a questo:

Mockito.doReturn(expected).when(target).toList1(Mockito.argThat(new MyVarargMatcher(objectArray))); 

Fonti:
How to properly match varargs in Mockito
http://maciejmadej.blogspot.com/2011/11/capturing-varargs-argument-using-custom.html

+0

Come ho accennato nella domanda, il codice mostrato è un esempio che rende facile vedere come il matcher non funziona con varargs. Il codice in cui ho un problema è di proprietà della mia azienda e ha un codice di stile di produzione con logica aziendale che non posso condividere. La domanda è se c'è un equivalente del matcher che funzionerà con varargs – raspacorp

+1

Ok ho creato un matcher personalizzato da usare, per favore fatemi sapere se funziona. – JLewkovich

+1

Sembra che la risposta sia: no non ci sono attualmente equivalenti equivalenti eq in Mockito per varargs, ma possiamo crearne uno uguale a quello che tu e il post di blog che hai postato. Ho implementato il mio e aggiunto anche un metodo che estrae la chiamata matcher in modo da poter scrivere eqVararg (objectArray) in questo modo: private Object [] eqVararg (Object ... vararg) {return Mockito.argThat (new VarargsMatcher (vararg)); } – raspacorp

0

Questo non è un problema con la corrispondenza di vararg. L'unica limitazione è che devi specificare ogni singola voce dell'array come argomento corrispondente. Ho aggiornato il codice qui sotto per mostrare cosa intendo. Ho creato un secondo objectArray2 per rendere più chiaro il punto. Tutti i test passano:

@RunWith(MockitoJUnitRunner.class) 
public class UnitTest { 
    private Object[] objectArray; 
    private Object[] objectArray2; 
    private List<Object> expected; 
    private TestTarget target; 
    private Object obj,obj2; 

    @Before 
    public void setUp() { 
     obj = new Object(); 
     obj2 = new Object(); 
     objectArray = new Object[]{ obj }; 
     objectArray2 = new Object[]{ obj, obj2 }; 
     expected = Arrays.asList(new Object(), new Object()); 
     target = Mockito.spy(new TestTarget()); 
    } 

    @Test 
    public void testMakeList() { // this pass as eq works well with normal array 
     doReturn(expected).when(target).toList(Mockito.eq(objectArray)); 
     Assert.assertEquals(expected, target.makeList(objectArray)); 
    } 

    @Test 
    public void testMakeList1() { // since objectArray has one entry you need to add one matching argument 
     doReturn(expected).when(target).toList1(Mockito.eq(obj)); 
     Assert.assertEquals(expected, target.makeList1(objectArray)); 
    } 

    @Test 
    public void testMakeListWithAryEq() { // since objectArray2 has two entries you need to add two matching arguments 
     doReturn(expected).when(target).toList1(Mockito.eq(obj),Mockito.eq(obj2)); 
     Assert.assertEquals(expected, target.makeList1(objectArray2)); 
    } 

    private class TestTarget { 
     public List<Object> makeList(Object[] objects) { 
      return toList(objects); 
     } 

     public List<Object> makeList1(Object[] objects) { 
      return toList1(objects); 
     } 

     protected List<Object> toList(Object[] objs) { 
      return null; // Not implemented "Intentionally" 
     } 

     protected List<Object> toList1(Object... objs) { 
      return null; // Not implemented "Intentionally" 
     } 
    } 
}