This is not your usual "my breakpoints don't work" question.
Consider the following code:
Runnable runnable = new Runnable()
{
@Override public void run()
{
Log.debug( "in run()" ); // <-- place one breakpoint here
}
};
@Test public void test()
{
Log.debug( "in test()" ); // <-- place another breakpoint here
runnable.run();
}
If you were to run this test from within IntellijIdea, using IntellijIdea's built-in JUnit support, the following things would happen:
However:
If you were to run this test from within some other framework, (e.g. Testana) which discovers the test class at runtime, loads it dynamically, and executes each test method in it, then the following happens:
test()
method hits.run()
method does not hit.As a matter of fact, when the breakpoint in the test()
method hits, you can see that the breakpoint in the run()
method remains a red circle without a checkmark, which means that IntellijIdea does not recognize it as being on executable code.
Just in case it matters, I am currently using macOS, in a few days I am hoping to be able to try under Windows.
There were a couple of similar issues in IntellijIdea reported and fixed a long time ago: https://youtrack.jetbrains.com/issue/IDEA-79268 (10 years ago) https://youtrack.jetbrains.com/issue/IDEA-133881 (7 years ago)
Judging by a comment by CrazyCoder (a well known JetBrainiac on Stackoverflow) from May 29 '13 at 13:11 on this question Line breakpoints don't work in some classes which mentions some "debug scope" I suspect that the problem is something along these lines:
test()
method hits.run()
method does not hit.And now the question:
Is there any workaround that would make the IntellijIdea debugger hit the breakpoint in the anonymous inner class?
Ideally, the workaround would be a general-purpose solution that can be implemented in the testing framework to take care of any similar situation.
A workaround that would make breakpoints work in anonymous inner classes by extra bureaucracy on the side of the test class would also be (barely) acceptable.
(But if you were going to suggest that I convert my anonymous inner class to a separate top-level class, please don't.)
EDIT
Behavior is same on Windows.
Steps to reproduce:
T01_CompilingIntertwine
run()
)Debug
key to bring up the run configurations dialogTestana - All
; launch it.new Runnable()
)Testana - All
.So, Konstantin Annikov from JetBrains found this worthy of creating an new issue for it on the IntelliJ IDEA issue tracker, see https://youtrack.jetbrains.com/issue/IDEA-287858
Then, Egor Ushakov from JetBrains looked into it, and found that this is happening because the testing framework is loading the classes in a non-standard order, while IntelliJ IDEA contains some logic that relies on the assumption that the classes will be loaded in the standard order.
The standard order of loading classes (when classes are being loaded by their classloader as they are being executed) is to have the outermost class loaded first, and the inner classes loaded afterwards.
Testana was loading the classes in the order in which the class files are yielded by java.nio.file.Files.walkFileTree()
, which is apparently alphabetic, and it just so happens that $
sorts before .
, so Testana was loading the inner classes first, and the outermost class last.
I fixed the problem in Testana, and Egor expressed the intention to try and implement a workaround for this case in IntelliJ IDEA. (This is such an edge case that I am not sure it is worth fixing, but anyway, it is his call.)