0

In Why JUnit 5 default access modifier changed to package-private, Sam Brannen's answer mentions how there is no need for defining public methods anymore following the principle of "less is more", which explains the reasoning behind this change (I think it's great!).

However, I still don't quite understand how it is technically possible.

In Why Junit test cases(Methods) should be public? (this is about JUnit 4), the accepted answer states:

If the methods were not public, calling them might fail (because the SecurityManager gets to veto that).

How and why is this no longer a problem in JUnit 5 when accessing package-private/protected methods through reflection?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Miss Skooter
  • 803
  • 10
  • 22
  • Also consider that almost no one actually uses a `SecurityManager`, especially not in contexts running unit tests, so that concern for JUnit 4 sounds rather exotic to me. – Mark Rotteveel Aug 30 '23 at 08:02

1 Answers1

1

JUnit 5 makes more extensive use of reflection. It has more power to find classes and methods, and also to inject values non-visible (private, package-private, etc.) members. I've seen some of their code use setAccessible(true) to make non-public fields and methods accessible.

However, this doesn't work well with the module system that was added in Java 9. You can solve that by using the --add-opens JVM flag. For more information about that, see https://stackoverflow.com/a/71296829/1180351

Rob Spoor
  • 6,186
  • 1
  • 19
  • 20
  • Thank you for your answer! I'm confused, you're basically saying that they modify the accessibility of the methods? And it's not actually fullproof? (in other words, non-compliant with what the JDK expects you to do?) Makes it sound quite hacky tbh. – Miss Skooter Aug 30 '23 at 07:57
  • A lot of frameworks used reflection to make things accessible, not just JUnit. Think of CDI or Spring. Before Java 9 a security manager was needed with a policy that explicitly denied making non-public members accessible. I've even created a POC that allowed me to make Strings mutable (since I could get access to the backing `char[]` at the time). That's one thing that Java's module system was designed to handle. You can still get around it, but you need to make it explicit now that you want to allow JUnit to make non-publics accessible. – Rob Spoor Aug 30 '23 at 08:02
  • Sorry I'm still a bit confused, it really sounds like you're saying they're making use of an exploit in java rather than something intended by the JDK developers? – Miss Skooter Aug 30 '23 at 11:50
  • 1
    I wouldn't call it an exploit. They are using a mechanism that has been provided by the JDK developers a long time ago. This mechanism could always be turned off using a security manager, and in modules actually has been turned off. Where before you had to explicitly turn it *off*, now you have to explicitly turn it *on*. – Rob Spoor Aug 30 '23 at 12:31