Java 17, Gradle 8.3 and Spring Boot 3.2.4 here. My build.gradle
looks like:
plugins {
id 'application'
id "io.freefair.lombok" version '6.4.0'
id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.4'
}
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
implementation (
'org.apache.commons:commons-lang3:3.12.0'
,'commons-io:commons-io:2.11.0'
,'org.projectlombok:lombok:1.18.16'
,"org.springframework.boot:spring-boot-starter"
,"org.springframework.boot:spring-boot-starter-actuator"
,"org.springframework.boot:spring-boot-starter-web"
,"org.springframework.boot:spring-boot-starter-data-jpa"
,"org.springframework.boot:spring-boot-starter-data-rest"
,"org.springframework.boot:spring-boot-starter-jdbc"
,"org.springframework.boot:spring-boot-starter-validation"
,"org.springframework.boot:spring-boot-starter-logging"
,"org.springframework.boot:spring-boot-starter-thymeleaf"
,"org.springframework.boot:spring-boot-starter-security"
,"org.springframework.boot:spring-boot-starter-oauth2-client"
,"org.springframework.boot:spring-boot-starter-mail"
,'mysql:mysql-connector-java:8.0.30'
,'org.liquibase:liquibase-core:4.26.0'
,'org.slf4j:log4j-over-slf4j:1.7.33'
)
testImplementation (
'org.springframework.boot:spring-boot-starter-test'
,'org.springframework.security:spring-security-test'
'org.junit.jupiter:junit-jupiter-api:5.8.1'
,'org.springframework.boot:spring-boot-starter-test'
,'org.springframework.security:spring-security-test'
,'com.h2database:h2:2.1.214'
,'org.mockito:mockito-core'
)
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}
tasks.named('test') {
useJUnitPlatform()
}
bootJar {
archiveFileName = "myapp.jar"
}
java {
sourceCompatibility = '17'
}
I have a base unit test class:
@SpringBootTest
public abstract class BaseUnitTest {
@BeforeEach
public abstract void setupForEach();
protected UserEntity createMockUser() {
return Mockito.mock(UserEntity.class);
}
protected OrgEntity createMockOrganization() {
return Mockito.mock(OrgEntity.class);
}
// other test helper methods
}
And a test class:
public class RegistrationServiceTest extends BaseUnitTest {
@MockBean
private UserService userService;
@MockBean
private OrgService orgService;
@Autowired
private RegistrationService registrationService;
@Override
public void setupForEach() {
}
@Test
public void inviteUser_whenInputIsGood_thenUserIsCreatedAndInviteIsSent() {
// setup
UserEntity newUser = createMockUser();
OrgEntity org = createMockOrganization();
when(userService.getByEmail(eq("some email"), anyBoolean())).thenReturn(null);
when(organizationService.getByRefId(anyString())).thenReturn(org);
// test
UserInvitationEntity result = registrationService.inviteUser(user);
// check
assertNotNull(result);
}
}
When I run this test class I get the following exception:
java.lang.NoSuchMethodError: 'org.junit.jupiter.api.extension.ExecutableInvoker org.junit.jupiter.api.extension.ExtensionContext.getExecutableInvoker()'
at org.springframework.test.context.junit.jupiter.SpringExtension.registerMethodInvoker(SpringExtension.java:381)
at org.springframework.test.context.junit.jupiter.SpringExtension.beforeAll(SpringExtension.java:132)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllCallbacks$10(ClassBasedTestDescriptor.java:381)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllCallbacks(ClassBasedTestDescriptor.java:381)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:205)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:80)
<large stacktrack omitted for brevity>
Suppressed: java.lang.NoSuchMethodError: 'org.junit.jupiter.api.extension.ExecutableInvoker org.junit.jupiter.api.extension.ExtensionContext.getExecutableInvoker()'
at org.springframework.test.context.junit.jupiter.SpringExtension.registerMethodInvoker(SpringExtension.java:381)
at org.springframework.test.context.junit.jupiter.SpringExtension.afterAll(SpringExtension.java:143)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeAfterAllCallbacks$16(ClassBasedTestDescriptor.java:447)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeAfterAllCallbacks$17(ClassBasedTestDescriptor.java:447)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeAfterAllCallbacks(ClassBasedTestDescriptor.java:447)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.after(ClassBasedTestDescriptor.java:229)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.after(ClassBasedTestDescriptor.java:80)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:161)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:161)
... 48 more
Don't worry about the coding/implementation of my test class/method, I'm curious as to why I'm getting this java.lang.NoSuchMethodError
. I suspect its incompatible versions of Java, Spring Boot and JUnit but I can't tell where I'm going wrong.
After removing the explicitly-managed JUnit, Mockito and H2 dependencies in my build.gradle
, I am still getting errors, but the error I am receiving has changed slightly:
java.lang.AbstractMethodError: Receiver class org.junit.jupiter.engine.descriptor.ClassExtensionContext does not define or inherit an implementation of the resolved method 'abstract org.junit.jupiter.api.extension.ExecutableInvoker getExecutableInvoker()' of interface org.junit.jupiter.api.extension.ExtensionContext.
at org.springframework.test.context.junit.jupiter.SpringExtension.registerMethodInvoker(SpringExtension.java:381)
at org.springframework.test.context.junit.jupiter.SpringExtension.beforeAll(SpringExtension.java:132)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllCallbacks$10(ClassBasedTestDescriptor.java:381)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllCallbacks(ClassBasedTestDescriptor.java:381)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:205)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:80)
<large stack trace omitted for brevity>
Suppressed: java.lang.AbstractMethodError: Receiver class org.junit.jupiter.engine.descriptor.ClassExtensionContext does not define or inherit an implementation of the resolved method 'abstract org.junit.jupiter.api.extension.ExecutableInvoker getExecutableInvoker()' of interface org.junit.jupiter.api.extension.ExtensionContext.
at org.springframework.test.context.junit.jupiter.SpringExtension.registerMethodInvoker(SpringExtension.java:381)
at org.springframework.test.context.junit.jupiter.SpringExtension.afterAll(SpringExtension.java:143)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeAfterAllCallbacks$16(ClassBasedTestDescriptor.java:447)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeAfterAllCallbacks$17(ClassBasedTestDescriptor.java:447)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeAfterAllCallbacks(ClassBasedTestDescriptor.java:447)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.after(ClassBasedTestDescriptor.java:229)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.after(ClassBasedTestDescriptor.java:80)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:161)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:161)
... 48 more
The problem is that you are including explicit dependencies for junit-jupiter-engine
and junit-jupiter-api
. You are including version 5.8.1 whereas I think Spring Boot 3.2 requires 5.10.
However you don't need those dependencies as those are already pulled in as part of the spring-boot-starter-test
. Removing them will also prevent you in future updates getting incompatible versions.
The solution remove the dependencies or at least the version number. But I would delete them all together.
dependencies {
implementation (
'org.apache.commons:commons-lang3:3.12.0'
,'commons-io:commons-io:2.11.0'
,'org.projectlombok:lombok'
,"org.springframework.boot:spring-boot-starter-actuator"
,"org.springframework.boot:spring-boot-starter-web"
,"org.springframework.boot:spring-boot-starter-data-jpa"
,"org.springframework.boot:spring-boot-starter-data-rest"
,"org.springframework.boot:spring-boot-starter-jdbc"
,"org.springframework.boot:spring-boot-starter-validation"
,"org.springframework.boot:spring-boot-starter-thymeleaf"
,"org.springframework.boot:spring-boot-starter-security"
,"org.springframework.boot:spring-boot-starter-oauth2-client"
,"org.springframework.boot:spring-boot-starter-mail"
,'com.mysql:mysql-connector-j'
,'org.liquibase:liquibase-core'
,'org.slf4j:log4j-over-slf4j'
)
testImplementation (
'org.springframework.boot:spring-boot-starter-test'
,'org.springframework.security:spring-security-test'
,'com.h2database:h2'
)
}
TIP: Mockito is also already pulled in by spring-boot-starter-test
and the H2 version is managed as well.
TIP2: Lombok is also managed by Spring Boot, remove that version as well to get a compatible version. Or at least use the most recent one as older versions tent not to work well with newer Java versions. (Or ditch Lombok altogether but that is another discussion ;) ).
TIP3: I changed the MySQL driver to the one managed by Spring Boot (and the newer coordinates).
TIP4: Your SLF4J version 1.7.33 wasn't compatible either as Spring Boot uses 2.0.x, remove the version or remove the dependency altogether as this is already pulled in automatically.
TIP5: You had duplicate dependencies in your testImplemementation
(Removed) and in your general implementation
you don't need the spring-boot-starter
and spring-boot-starter-logging
as those are pulled in by all other spring-boot-starter-*
dependencies already.