Gradle 5 JUnit BOM and Spring Boot Incorrect Versions

I am using Gradle 5's BOM (Bill of Materials) feature. This is how I describe it for my JUnit 5 dependencies:

testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
testImplementation("org.junit.jupiter:junit-jupiter-params")

My assumption is that providing the BOM will resolve the versions of the dependencies to 5.4.0. However, they get resolved to 5.1.1. I am not sure why. (I also request enforcedPlatform() to lock the specified version)

enter image description here

Inspecting JUnit 5's BOM we see that all org.junit.jupiter dependencies are listed with version 5.4.0 (resolving to 5.1.1 in the project) and all org.junit.platform dependencies are listed with version 1.4.0 which resolve correctly in the project.

I am not sure what I am missing and was hoping to get some help here. Thanks!

EDIT:

I used Sormuras response and moved all BOMs at the top of the dependencies {} block but was still not getting version 5.4.0. Then I suspected it might be coming from the Gradle Spring Dependency Management plugin that I use, so when I commented it out, I got version JUnit 5.4.0. How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?

Gradle Spring Dependency Management plugin

FINALLY:

I decided to use the Spring Boot Dependencies BOM directly and remove the Gradle plugin:

implementation(platform("org.springframework.boot:spring-boot-dependencies:2.0.5.RELEASE"))

I imagine the plugin was created for those version of Gradle before Gradle 5 where you couldn't use a BOM file. Now with the BOM support I can directly include it. This way my version of JUnit is as I have specified it in the enforcedPlatform() block.

I accepted Sam Brannen's answer below because he explains well how the issue occurs and what solves it and I think it's relevant for those who use older versions of Gradle.


Solution 1:

How do I disable JUnit coming from the Gradle Spring Dependency Management plugin?

For starters, if you are using the dependency management plugin from Spring, you should not be importing the junit-bom since that results in duplicate (and potentially conflicting) management of those dependencies.

Aside from that, whenever you use the dependency management plugin from Spring and want to override a managed version, you have to do it by overriding the exact name of the version defined in the BOM used by the plugin.

This is documented in Spring Boot for Gradle and for Maven.

For Spring Boot the name of the JUnit Jupiter version is "junit-jupiter.version". You can find the names of all managed versions for Spring Boot 2.1.2 here.

So, in Gradle you would override it as follows.

ext['junit-jupiter.version'] = '5.4.0'.

You can see that I have done exactly that here.

With Maven you would override it as follows.

<properties>
    <junit-jupiter.version>5.4.0</junit-jupiter.version>
</properties>

Further background information here: https://docs.spring.io/platform/docs/current/reference/html/getting-started-overriding-versions.html

Solution 2:

JUnit 5.4.0 simplified its artifacts, and now delivered a single artifact for Jupiter - org.junit:junit-jupiter. I.e., you should simplify your Gradle file too:

testImplementation(enforcedPlatform("org.junit:junit-bom:5.4.0")) // JUnit 5 BOM
testImplementation("org.junit.jupiter:junit-jupiter")

Solution 3:

Ensure to include JUnit's BOM before other BOMs that also refer to JUnit. First BOM wins and locks version of all later artifacts.

See this issue for a similar setup using Maven and Spring Boot: https://github.com/sormuras/junit-platform-maven-plugin/issues/29#issuecomment-456958188