2

メソッドのコードに命令を追加したい。これらの命令は、メソッドに到達した後、メソッドを終了する前に実行する必要があります。最後の命令が終了する前に常に実行されるようにするために、これらをfinallyブロックに入れたいと思います。(私はクラスを知ってAdviceAdapterいますが、呼び出されたメソッドが例外をスローしたときに終了コードの実行を保証しません。)

私の問題は、結果の指示が間違った順序になっていることです。

処理方法:

@Test
public void original() {
    assertTrue(true);
    assertTrue(!(false));
}

望ましい結果:

@Test
public void desired() {
    //some logging X

    try {
        assertTrue(true);
        assertTrue(!(false));
    }
    finally {
        //some logging Y
    }
}

(ログ X は、try ブロックの最初の行でも発生する可能性があります。)

(目的の結果のバイトコードは、次の Java コードのバイトコードと同じです:)

@Test
public void desired() {
    //some logging X

    try {
        assertTrue(true);
        assertTrue(!(false));
        //some logging Y
    }
    catch (Throwable t) {
        //some logging Y
        throw t;
    }
}

ASM を使用してメソッドを処理する私のコード:

@Override
public void visitCode() {
    before();

    super.visitCode();

    after();
}

private void before() {
    insertInstructionToSetMode(LoggingMode.TESTING);

    this.l0 = new Label();
    this.l1 = new Label();
    visitLabel(l0);
}

private void after() {
    visitTryCatchBlock(l0, l1, l1, null);
    Label l2 = new Label();
    visitJumpInsn(GOTO, l2);
    visitLabel(this.l1);
    visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] {"java/lang/Throwable"});
    visitVarInsn(ASTORE, 1);

    insertInstructionToSetMode(LoggingMode.FRAMING);

    visitVarInsn(ALOAD, 1);
    visitInsn(ATHROW);
    visitLabel(l2);
    visitFrame(Opcodes.F_SAME, 0, null, 0, null);

    insertInstructionToSetMode(LoggingMode.FRAMING);
}

private void insertInstructionToSetMode(LoggingMode mode) {
    String modeValue = (mode == LoggingMode.TESTING ? FIELD_NAME_TESTING : FIELD_NAME_FRAMING);

    visitFieldInsn(Opcodes.GETSTATIC, CP_LOGGING_MODE, modeValue, FIELD_DESC_LOGGING_MODE);
    visitMethodInsn(INVOKESTATIC, CP_INVOCATION_LOGGER, METHOD_NAME_SET_MODE, METHOD_DESC_SET_MODE);
}

生成されたバイトコード(命令の順序が間違っています):

// logging X
01 getstatic instrumentation/LoggingMode/TESTING Linstrumentation/LoggingMode;
02 invokestatic instrumentation/InvocationLogger/setMode(Linstrumentation/LoggingMode;)V

// successfully passed the try block
03 goto 9

// catch block for the finally behaviour
04 astore_1
05 getstatic instrumentation/LoggingMode/FRAMING Linstrumentation/LoggingMode;
06 invokestatic instrumentation/InvocationLogger/setMode(Linstrumentation/LoggingMode;)V
07 aload_1
08 athrow

// logging Y
09 getstatic instrumentation/LoggingMode/FRAMING Linstrumentation/LoggingMode;
10 invokestatic instrumentation/InvocationLogger/setMode(Linstrumentation/LoggingMode;)V

// original code
11 iconst_1
12 invokestatic org/junit/Assert/assertTrue(Z)V
13 iconst_1
14 invokestatic org/junit/Assert/assertTrue(Z)V
15 return

01-02 は問題ありませんが、09-10 は元のコード (14) の後、return 命令の前にする必要があります。 11-14 は 03 より前である必要があります。

4

3 に答える 3

2

エラーがあなたのアプローチのどこにあるのかわかりません。しかし、AdviceAdapter を使用して試行錯誤を繰り返した結果、このような結果が得られました。

見る

http://code.google.com/p/pitestrunner/source/browse/pitest/src/main/java/org/pitest/coverage/codeassist/CoverageMethodVisitor.java

于 2013-06-26T16:34:22.390 に答える