4

The questions Debug Partial Mock in JMockit and Debugging Java code tested with Spock and JMockit already deal with the issue, that breakpoints in your software under test (SUT) get ignored when the class gets redefined/instrumented by JMockit. The recommended solution is that you should add an additional breakpoint in your testclass in order to re-activate the breakpoints in SUT, once the execution stops in your testclass.

However, this solution does not work, if you are using the @Tested annotation in your testclass, because in this case the breakpoint in the testclass itself gets ignored.
Here is an example:

package de.playground;

import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import mockit.Expectations;
import mockit.Injectable;
import mockit.integration.junit4.JMockit;

@RunWith(JMockit.class)
public class DebuggingWithJMockitTest {

    public interface Collaborator {
        String execute(String... args);
    }

    public static class ToTest {
        private Collaborator collaborator;

        public ToTest(Collaborator collaborator) {
            this.collaborator = collaborator;
        }

        public String doSomething() {
            return collaborator.execute("a", "b");
        }
    }


    @Injectable
    private Collaborator collaborator;

    @Tested
    private ToTest toTest;    

    @Test
    public void testHoldOnBreakpoint() {
        new Expectations() {{
                collaborator.execute((String[]) any); result = "whatever";
            }};

        String result = toTest.doSomething(); // add breakpoint here
        assertThat(result, is("whatever"));
    }
}

In this case the debugger does not stop in the String result = toTest.doSomething(); line. If you do not use the @Tested annotation and initialize the SUT in a @Beforemethod like this:

    // @Tested is not used
    private ToTest toTest;

    @Before
    public void before() {
        toTest = new ToTest(collaborator);
    }

the breakpoint works perfectly fine.

Is there any workaround how you can debug your code even if you are using the @Testedannotation in the test class?

Community
  • 1
  • 1
Joern
  • 1,926
  • 1
  • 13
  • 18
  • No idea yet, but something was changed between JMockit 1.22 and 1.23 which is causing this... I will open an issue for it. – Rogério May 04 '16 at 15:30
  • I found out why it happens now: JMockit 1.23 added support for JDK 9, and that required it to use `Instrumentation#retransformClasses(...)` as a way to obtain the bytecode of a test or tested class. The problem is, due to a JVM limitation, class redefinition/retransformation causes all current breakpoints on said classes to be dropped. – Rogério May 04 '16 at 15:49
  • 1
    I can confirm that the breakpoint in the test class is still working with version 1.22 but not with version 1.23. If I find some time I'll try to dig into it a little bit more. Maybe there exist some workarounds to reset the breakpoints after redefining the classes.... – Joern May 09 '16 at 06:11

1 Answers1

2

This bug was brought up on the JMockit Google Group:

Yes, the problem is known, and already solved in JMockit 1.24.

It doesn't look like there was an issue logged for it. Our team ran into this issue on JMockit 1.23 and indeed was able to overcome it by upgrading to JMockit 1.24.

Thunderforge
  • 19,637
  • 18
  • 83
  • 130