First of all I would like to state that I'm fairly new to Spring Boot and Spring Cloud.
I have the following project setup:
- Consumer Driven Contracts are stored in a Git repository following this guide. Producer has to answer to two consumers accessing two different endpoints, so there is no conflict there.
- Producer is setup following the same guide to fetch contracts from the remote.
- Both projects are set up using Maven.
Dependencies on the producer side are:
- Spring Boot 3.0.2
- Spring Cloud Contract Verifier 4.0.1
- Spring Cloud Contract Maven Plugin 4.0.1
- Spring Security 6.0.1 and Spring Security Test (unrelated but probably important)
When using the routines spring-cloud-contract:generateTests everything runs fine and tests are generated in the proper directory, then when running the lifecycle routine test and those generated contract tests are run they produce the following error:
NoClassDefFoundError: javax/servlet/Filter
at com.projectId.artifactId.contracts.ConsumerTest.validate_shouldReturnApplicationRoles(ConsumerTest.java:113)
projectId, artifactId, ConsumerTest are placeholders for the real package, artifact name and consumer name respectively. Sample of the method where it fails (all generated tests fail and give the same error, line 113 in this case refers to the point of get("/auth/v1/role")):
public class ConsumerTest extends BaseTestClass {
@Test
public void validate_shouldReturnApplicationRoles() throws Exception {
// given:
MockMvcRequestSpecification request = given();
// when:
ResponseOptions response = given().spec(request)
.get("/auth/v1/role");
// then:
assertThat(response.statusCode()).isEqualTo(200);
assertThat(response.header("Content-Type")).matches("application/json.*");
assertThat(response.header("Access-Control-Allow-Origin")).isEqualTo("*");
// and:
DocumentContext parsedJson = JsonPath.parse(response.getBody().asString());
assertThatJson(parsedJson).array().contains("['id']").isEqualTo(1);
assertThatJson(parsedJson).array().contains("['name']").isEqualTo("Acotado");
assertThatJson(parsedJson).array().contains("['description']").isEqualTo("Acceso acotado en un espacio temporal desde que se crea la clave");
assertThatJson(parsedJson).array().contains("['id']").isEqualTo(2);
assertThatJson(parsedJson).array().contains("['name']").isEqualTo("Ilimitado");
assertThatJson(parsedJson).array().contains("['description']").isEqualTo("Acceso ilimitado");
}
}
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.ActiveProfiles;
@ActiveProfiles("test")
public abstract class BaseTestClass {
@Autowired
AuthorizationController authorizationController;
@Autowired
IdentityController identityController;
@MockBean
AuthorizationService authorizationService;
@MockBean
IdentityService identityService;
@BeforeEach
public void setup() {
RestAssuredMockMvc.standaloneSetup(authorizationController, identityController);
}
}
The test profile just configures a context path and a h2 instance for the integration tests of the application.
I have tried different BaseClasses for tests and expected the tests to pass or at least to fail in a meaningful way. What is failing here? I have a suspicion that Spring Security has something to do with that error...
Update
On an empty project with only Spring Boot and Spring Cloud Contract as dependencies the test do run and sure do fail but as expected in a meaningful way (comparing responses expected against obtained). BaseClass does differ a little bit since on this trial scenario there is only a mock controller.
Update 2
I've added Spring Security to the aforementioned mock project and that has been enough to make it fail to compile. I have tried with two BaseTestClass definitions, one following Spring Cloud Contract's guidelines (which is the one that worked previously) and another following Spring Security's guides on MockMvc, both below by mention order:
class BaseTestClass {
@BeforeAll
public static void setup() {
RestAssuredMockMvc.standaloneSetup(new TrialController);
}
}
class BaseTestClass{
MockMvc mockMvc;
@BeforeEach
void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new TrialController()).build();
}
}
Neither manages to run the application nor the test producing either IllegalState errors or spring test delegate cannot be null.
Okay so after countless hours of going back and forth through the many (and confusing) Spring Docs pages and guides and reading many almost related SO questions and answers here is how I got the application and the tests running.
The
BaseTestClassshould look like this:The
ActiveProfilesannotation is just necessary if you need any application configuration for the tests to run, in my case the connection to an h2 instance.The
TestInstanceannotation is to allow theBeforeAllannotated method not to be static in the same fashion as the docs use JUnit4'sBefore.Hope it helps somebody else.