Matt's Tidbits (28 Part Series)
Last time I shared a story (and some lessons learned) to share around a recent website deployment. This week, I have a story about some odd breakpoint behavior.
Recently I was debugging a unit test and was very puzzled because one of my breakpoints was not being hit. The breakpoint was in Kotlin code, inside of a lambda that was being called as a result of a Rx subscription (if you've worked with code like this, you probably understand why I was trying to debug it!)
I'm no stranger to having issues with breakpoints in Kotlin, so I quickly ticked through my mental list of known issues (and previous tidbits, especially #14) and first checked that the breakpoint was actually being set at runtime. I quickly that the breakpoint was not receiving the check mark that it should have been. This seemed like a perfectly valid line of code, but just on a whim I tried some of my other tricks - converting unit tests written with Kotlin's
` syntax to use underscores instead. That unfortunately didn't help either.
So, I started experimenting to see if any breakpoints would work, and finally found that one did - I just had to set it much earlier in the program. What I found next really startled me - what I discovered almost by accident was that the breakpoint I was most interested in had now received the checkmark - but only once the program was paused. I tested this a few more times, and verified that I wasn't crazy - as long as I had a breakpoint earlier on in the program, the breakpoint I wanted would successfully pause. If I took out the earlier breakpoint though, the program would never stop on my breakpoint.
This smelled like some kind of race condition to me - adding a delay (in this case, pausing the program before that breakpoint was evaluated) caused something else to happen/load which resulted in the expected behavior. I wasn't sure why this was happening, but drawing on my experience with debugging complex/unknown problems (see tidbit #35) - I started by switching to an older version of the code and testing this behavior there.
I found that in the older version of code my breakpoint worked fine. So, something had changed that was causing this to happen. As part of my current work I had just finished a large code merge, so I decided to re-review what I had done. In doing that, I discovered the crucial missing piece - the way that RxJava schedulers were being set up (specifically for tests) had changed, and I had done the merge incorrectly. What I had written compiled just fine, but I had neglected to notice that some of the other auto-merged code written by other members of my team set things up in a different way than I had been doing on my branch.
Upon correcting that error, I was thrilled to discover that the program now paused on my breakpoint as expected!
To recap, if you run into a case where a breakpoint in a unit test isn't working, you should:
- Check that the breakpoint has the checkmark icon at runtime - if not, your program won't pause.
- If it doesn't have the checkmark, and you're positive that it should (and you've tried the steps from Tidbit #14 above to rule out issues with Android Studio/Kotlin), try adding a breakpoint somewhere early on in the execution of your program - at a point before your other one should be hit.
- If this 2nd step causes your breakpoint to receive the checkmark, then check whether that unit test now passes - it's possible it will!
- If the 3rd step happens, then you definitely have an issue with your RxJava scheduler configuration. Double-check that code, and you will likely find the issue!
I hope you learned something that helps you the next time you're debugging some strange unit test failures. Please share your strangest debugging horror story in the comments below - I'd love to hear from you! And, please follow me on Medium if you're interested in being notified of future tidbits.
Interested in joining the awesome team here at Intrepid? We're hiring!
This tidbit was discovered on January 22, 2020.