Home » Mockito
Archiv der Kategorie: Mockito
Dynamische Mocking
Probleme:
Problem 1: Dynamisches Mocking:
Eine Methode soll Mocks für verschiedene Service-Klassen definieren. In der Methode selbst kann nicht jede in ihr zu Mockende Klasse separat auscodiert werden.
D.h.:
Mockito.when(MeineKlasse.meinMethode())
ist nicht möglich.
Stattdessen wird der Methode ein Class -Objekt übergeben, die den zu mockenden Service definiert.
Problem 2:
Wenn ein bestimmter request vorliegt muss ein definierter Reply zurück gegeben werden.
MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(new Bohne1("X"))).thenReturn("desired return");
Problem 3 :
Definition einer Sequenz der durch den Mock zurückzugebender Return-Werte.
MyObj2 mock = Mockito.mock(MyObj2.class);
Mockito.when(mock.returnOnObj(Mockito.any())).thenReturn("1").thenReturn("2").thenReturn("3");
Beispiel, das alles obigen Probleme löst:
HPServiceMockFactory.class
import org.mockito.stubbing.OngoingStubbing;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.when;
public class HPServiceMockFactory<T> {
public enum MockMatchingType {IN_SEQUENCE, BY_REQUEST_MATCH};
public <T> T prepareMock(T mock, Class bdType, String svcName, MockMatchingType mockMatchingType, Object[] parameters, Object[] desiredReturns){
Method svc = null;
for (Method method : bdType.getDeclaredMethods()) {
// check if method with this name and number of arguments is declared
if ((method.getParameterTypes().length == parameters.length) && (method.getName().equals(svcName))) {
// check method parameters
if (allinstanceof(parameters, method.getParameterTypes())) {
try {
Object[] paramsForInvocation = new Object[parameters.length];
for(int i = 0; i < parameters.length; i++){
if(mockMatchingType.equals(MockMatchingType.IN_SEQUENCE)){
// When we want to invoke in sequence: First invocation gets desiredReturn[0], second gets desiredReturn[1], ...
// Then we should narrow only to anyObject parameters (or we could narrow the the suiting parameter classes)
paramsForInvocation[i] = anyObject();
}else{
// When we want the mock to return an answer which is defined by its request being equal as the one when the mock is called
// then we have to call the mock and pass the expected parameters BEFORE (farther below) define the return values (via the "thenReturn(..))
paramsForInvocation[i] = parameters[i];
}
}
svc = bdType.getDeclaredMethod(svcName, method.getParameterTypes());
svc.invoke(mock, paramsForInvocation);
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
} catch (InvocationTargetException e) {
throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to initialize mock data, " + e.toString(), e);
}
}
}
}
if (svc == null) {
throw new IllegalStateException("Service method could not be found");
}
OngoingStubbing<Object> ongoingStubbing = when(svc);
for(Object desiredReturn : desiredReturns){
ongoingStubbing = ongoingStubbing.thenReturn(desiredReturn);
}
return mock;
}
private boolean allinstanceof(Object obj[], Class<?> classes[]) {
for (int i = 0; i < obj.length; i++) {
Class<?> clazz = classes[i];
Object o = obj[i];
if (clazz.isPrimitive()) {
if (clazz == boolean.class) {
if (!(o instanceof Boolean)) {
return false;
}
} else if (clazz == int.class) {
if (!(o instanceof Integer)) {
return false;
}
}
} else {
if (o != null && !clazz.isInstance(o)) {
return false;
}
}
}
return true;
}
}
Test Klassen:
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.Objects;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.BY_REQUEST_MATCH;
import static com.ubs.m0m.mock.HPServiceMockFactory.MockMatchingType.IN_SEQUENCE;
/**
* Demonstrates how Mockito.when(null) can be used to tell Mockito to
* return a given value if objects equals to given ones are passed to the mocked method
*/
public class HPServiceMockTest {
@Test
public void mustReturnMockAnswersAsDefinedInASequence(){
HPService mockedObject = Mockito.mock(HPService.class);
Object[] parameters = new Object[1];
parameters[0] = new Bohne1("X");
String[] desiredReturns = {"Response 1", "Response 2", "Response 3"};
HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", IN_SEQUENCE, parameters, desiredReturns);
Assert.assertEquals(desiredReturns[0], mockedObject.returnOnObj(new Bohne1("ANY")));
Assert.assertEquals(desiredReturns[1], mockedObject.returnOnObj(new Bohne1("ANY")));
Assert.assertEquals(desiredReturns[2], mockedObject.returnOnObj(new Bohne1("ANY")));
}
@Test
public void mustReturnMockAnswersThatMatchTheGivenRequest(){
HPServiceMockFactory myServiceMockFactory = new HPServiceMockFactory<HPService>();
HPService mockedObject = Mockito.mock(HPService.class);
Object[] whenReqParams1 = new Object[1];
whenReqParams1[0] = new Bohne1("Request that must match 1");
String[] desiredReturns1 = {"Right Response 1"};
myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH, whenReqParams1, desiredReturns1);
Object[] whenReqParams2 = new Object[1];
whenReqParams2[0] = new Bohne1("Request that must match 2");
String[] desiredReturns2 = {"Right Response 2"};
myServiceMockFactory.prepareMock(mockedObject, HPService.class, "returnOnObj", BY_REQUEST_MATCH, whenReqParams2, desiredReturns2);
Assert.assertEquals(desiredReturns1[0], mockedObject.returnOnObj(new Bohne1("Request that must match 1")));
Assert.assertEquals(desiredReturns2[0], mockedObject.returnOnObj(new Bohne1("Request that must match 2")));
Assert.assertNull(mockedObject.returnOnObj(new Bohne1("ANY")));
}
}
class HPService {
public String returnOnObj(Bohne1 in){return "not mocked";}
}
class Bohne1 {
public String id;
public Bohne1(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Bohne1)) return false;
Bohne1 bohne1 = (Bohne1) o;
return Objects.equals(id, bohne1.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
... code ...
Mockito.when(null) – Return basierend auf equality zu gegebenem Input
Mockito.mock(null)
Weshalb sollte das sinn machen?
Mockito.when(null).thenReturn(meinObjekt)
bedeutet eigentlich: Liebes Mockito. Nimm den letzten Aufruf auf irgend einem Mock. Wenn irgendwann derselbe Aufruf mit denselben Parametern gemacht werden sollte, dann gib „meinObjekt“ zurück.
Dies wird unten demonstriert.
import org.mockito.Mockito;
import java.util.Objects;
/**
* Demonstrates how Mockito.when(null) can be used to tell Mockito to
* return a given value if objects equals to given ones are passed to the mocked method
*/
public class HPTest {
public static void main(String[] args) {
MyObj mockedObject = Mockito.mock(MyObj.class);
/* Tell Mockito, that if get1() is called, then return "super cool string 1.1"*/
mockedObject.get1();
Mockito.when(null).thenReturn("super cool string 1.1");
mockedObject.get2();
Mockito.when(null).thenReturn("super cool string 2");
System.out.println(mockedObject.get1());
System.out.println(mockedObject.get1());
System.out.println(mockedObject.get2());
System.out.println(mockedObject.toString());
/* Tell Mockito, that if return1("1") is called, then return "Return 1" */
mockedObject.return1("1");
Mockito.when(null).thenReturn("Return 1");
/* but if return1("2") is called, then return "Return 2" */
mockedObject.return1("2");
Mockito.when(null).thenReturn("Return 2");
System.out.println(mockedObject.return1("1"));
System.out.println(mockedObject.return1("2"));
System.out.println(mockedObject.return1("2"));
System.out.println(mockedObject.return1("1"));
mockedObject.returnOnObj(new Bohne("A"));
Mockito.when(null).thenReturn("On Obj A");
mockedObject.returnOnObj(new Bohne("B"));
Mockito.when(null).thenReturn("On Obj B");
System.out.println(mockedObject.returnOnObj(new Bohne("A")));
System.out.println(mockedObject.returnOnObj(new Bohne("B")));
System.out.println(mockedObject.returnOnObj(new Bohne("B")));
System.out.println(mockedObject.returnOnObj(new Bohne("A")));
}
}
class MyObj {
public String get1(){return "not mocked 1";}
public String get2(){return "not mocked 2";}
public String return1(String in){return "not mocked";}
public String returnOnObj(Bohne in){return "not mocked";}
}
class Bohne {
public String id;
public Bohne(String id) {
this.id = id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Bohne)) return false;
Bohne bohne = (Bohne) o;
return Objects.equals(id, bohne.id);
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
/*
Output:
super cool string 1.1
super cool string 1.1
super cool string 2
Mock for MyObj, hashCode: 650023597
Return 1
Return 2
Return 2
Return 1
On Obj A
On Obj B
On Obj B
On Obj A
Process finished with exit code 0
*/