Manchmal hat man die Situation, dass man sicherstellen möchte, dass eine Methode keine Implementierung besitzt.
Sei es, dass sie vererbt wurde und leergelassen werden soll oder andere motivierende Gründe vorliegen.

Ich habe eine Checker-Klasse geschrieben, die mir erlaubt, verschiedenste void-Methoden (mit oder ohne Parameter) auf eine leere Implementierung zu testen.


import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.mockito.internal.util.reflection.Whitebox;

public class Checker {
private Object sut;
private JavaClass classToCheck;

public Checker(Object objectToTest) {
    sut = objectToTest;
    classToCheck = Repository.lookupClass(sut.getClass());
}

public void assertEmptyVoidMethod(String methodName, Class<?>... parameterTypes) {
    Method methodToCheck = null;
    try {
        methodToCheck = classToCheck.getMethod(sut.getClass().getMethod(methodName, parameterTypes));
    } catch (NoSuchMethodException e) {
        fail("There is no method with name "
           + methodName
           + " inside the class "
           + sut.getClass().toString());
    } catch (Exception e) {
        fail("There are (security) problems with "
           + methodName
           + " inside the class "
           + sut.getClass().toString());
    }
    assertTrue("Method implementation must be empty.",
          ((Integer) Whitebox.getInternalState(methodToCheck.getCode(),
                                               "code_length")).intValue() == 1);
}

}

In einigen Fällen gab es Probleme beim Zugriff auf das interne Attribut code_length, was mit folgendem Code Segment umgangen werden konnte:

...
Code code = methodToCheck.getCode();

assertThat("Method implementation must be empty.",
   ((Integer) code.getLocalVariableTable().getLocalVariable(0).getLength()), is(Integer.valueOf(1)));

Benutzt wird der Checker dann wie folgt:

MyInterface sut = new MyClass();
sut.doNothing();
new Checker(sut).assertEmptyVoidMethod("doNothing");
new Checker(sut).assertEmptyVoidMethod("doNothingWithParameters",
                                String.class,
                                Integer.TYPE, // 2.Parameter Typ int
                                Double.TYPE); // 3.Parameter Typ double

Sollte der Test fehlschlagen, erhält man einen AssertionError, der folgenden Art:

java.lang.AssertionError: Method implementation must be empty.
    at org.junit.Assert.fail(Assert.java:88)
    at org.junit.Assert.assertTrue(Assert.java:41)
    at de.mike.test.utils.Checker.assertEmptyVoidMethod(Checker.java:30)
    at playaround.MyClassTest.testDoNothing(MyClassTest.java:13)
    ...

Die getestete Klasse MyClass hat dabei u.U. folgendes Aussehen:

public class MyClass extends MyBase implements MyInterface {

    /**
     *
     */
    @Override
    public void doNothing() {
    }

    /**
     * @param a
     * @return
     */
    public void doNothingWithParameters(String a, int b, double c) {
        // nothing to do.
    }

    ...
}

Man mag sich über Sinn und Unsinn eines solchen Tests seine Gedanken machen. Am Ende bleibt die Erkenntnis: Es ist möglich.

Test empty implementation
Markiert in:     

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.