Mocks erzeugen für via Class spezifizierte Objekte

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.

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;
    }
}

Aufrufende Klasse:

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);
    }
}

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
 */

 

Fehler: SunCertPathBuilderException: unable to find valid certification path to requested target (SSL handshake)

Fehler:

sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Lösung

In dem mir vorliegenden Fall musste die ein CA-Certifikat (welches das vom Server vorgezeigte Certifikat beglaubit) in den lokalen Truststore zugefügt werden.

–> Im vorliegenden Fall kann sich der Server nicht beim Caller authentifizieren.

Debugging-Möglichkeit:

-Djavax.net.debug=all

(In der Run-Config z.B. der Tomcat-Instanz)

Das bewirkt, dass interessantes geloggt wird unter: org.apache.cxf.transport.http.HTTPConduit

Auszüge davon:

Die Certificate-Chain

*** Certificate chain
chain [0] = [
[
 Version: V3
 Subject: CN=myserver.hps.com, OU=Server, OU=CA, O=UBS, C=CH
...
AuthorityInfoAccess [
 [
 accessMethod: caIssuers
 accessLocation: URIName: http://certinfo-http.hps.com/aia/HPS_Server_CA_Test_3.crt
 ...
]
SubjectAlternativeName [
 DNSName: hps.alternative.server.com
 ...
]
]

chain [1] = [
[
 Version: V3
 Subject: CN=HPS Server CA Test 3, OU=CH 027, OU=CA, O=UBS, C=CH
 ...

]

Unter „AuthorityInfoAccess“ wird für das Certifikat ausgewiesen, durch welches andere Certifikat es beglaubigt ist. Jenes Certifikat ist auch weiter unten noch separat ausgewisen.

Das „SubjectAlternativeName“ weist alterntiven Addressen aus, für welche dieses Zertifikat als „Ausweis“ dienen kann. Alternatife zu jenem, welches in parameter „subject“ definiert ist.

Die folgende Zeile sagt, dann „certificate_unknown„, was darauf hin deutet, dass die CA (HPS Server CA Test 3) (das Ende der oben beschribenen Chain nicht bekannt is. Das heisst sie ist nicht in unserem TrustStore vorhanden.

http-apr-8080-exec-9, SEND TLSv1 ALERT: fatal, description = certificate_unknown

 

 

Robocopy – Ersatz für xcopy – Windows-Backup über differenzierendes Kopieren (Mirroring) (Backup)

Anwendung:

robocopy source dest /MIR /XX

/MIR : Mirroring. Das heisst es wird gewährleistet, dass der Zielordner gleich aussieht wie der Source-Odner (wobei es sich bei „source“/“dest“ um Ordner handelt

/XX : Keine Löschungen von Files/Ordnern, die nur im Ziel vorkommen. (kompromittiert dahingehend das /MIR flag :-))

 

Referenz:

https://social.technet.microsoft.com/wiki/contents/articles/1073.robocopy-and-a-few-examples.aspx#Copy_all_changes

 

Schließen