JUnit tests in Spring Boot 3.0 does not work - spring-boot

Code
GET method inside controller class:
#GetMapping("/getAllRecommendedMovies")
public ResponseEntity<BookMyTicket> getAllRecommendedMovies(
#RequestParam(value = "theatreName", required = false) String theatreName,
#RequestParam(value = "pincode", required = false) Integer pincode,
HttpServletRequest request) {
return Observation.createNotStarted(
request.getRequestURI().substring(1),
observationRegistry
).observe(() -> new ResponseEntity<(
theatreManagementService.getAllRecommendedMovies(theatreName, pincode),
HttpStatus.OK
));
}
JUnit test:
#Test
public void getAllRecommendedMovies() throws Exception {
try (MockedStatic<Observation> utilities = Mockito.mockStatic(Observation.class)) {
utilities.when(
() -> Observation.createNotStarted(Mockito.eq("getAllRecommendedMovies"), Mockito.any())
).thenReturn(Observation.NOOP);
}
mockMvc.perform(get("/getAllRecommendedMovies")).andExpect(status().isOk());
}
Also on Github: TheatreManagementControllerTest.java
Question
I have implemented JUnit test for ObservationRegistry.
Is there any alternate method to implement?

Mockito.mockStatic can only mock static calls that happen in the same thread. See https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks.
Spring MVC tests run the Spring application in its own thread so static mocking with Mockito won't help here.
I suggest you introduce a ObservationService interface to wrap methods like Observation.createNotStarted(..) and use that service in your controller. The service can then be easily mocked using standard Spring testing mechanisms like #MockBean.

Related

java.lang.IllegalArgumentException: CamelContext must be specified on: Message[] - Camel core

Below is builder from camel core & writting junit testcases with it & camel core version used is 2.22.1.
new ExchangeBuilder(null)
.withBody(body)
.withHeader(header, headerValue)
.build();
Junit testcases is throwing error when calling above builder - java.lang.IllegalArgumentException: CamelContext must be specified on: Message[]
You'll have to provide constructor of ExchangeBuilder a instance of CamelContext. If your test class inherits from CamelTestBuilder you can use context() method to obtain it during a test.
public class SomeTest extends CamelTestSupport {
#Test
public void testSomething(){
String body = "some body";
String header = "SomeHeader";
String headerValue = "Some header value";
ExchangeBuilder builder = new ExchangeBuilder(context())
.withBody(body).withHeader(header, headerValue);
Exchange exchange = builder.build();
CamelContext contextFromExchange = exchange.getContext();
// Do something with the exchange?
}
}
If you're not using one of the camel-test modules you'll have to create and configure one manually using e.g new DefaultCamelContext();. For testing routes use of one of the camel-test modules is highly recommended though as they make things a lot easier.

How can I test logs of Spring Boot application?

I have an application that is a mix of Spring Boot, Jersey, and Camel applications. It starts as a Spring Boot app. I am writing integration tests, and I need to make asserts on logs?
For instance, I need to assert that the Camel route read a message from source A. How can I make reliable asserts on logs? Is there any industry standard for this?
NOTE: I tried finding any solution, but at the moment, I neither understand how to solve it nor can find ready solutions.
UPDATE 1: The detail that I underestimated, but it seems important. I use Kotlin, NOT Java. I tried applying answer, but it isn't one to one transferable to Kotlin.
UPDATE 2:
This is a conversion from Java to Kotlin. ListAppender doesn't have enough information to resolve the type in Kotlin.
class LoggerExtension : BeforeEachCallback, AfterEachCallback {
private val listAppender: ListAppender<ILoggingEvent> = ListAppender<ILoggingEvent>()
private val logger: Logger = LoggerFactory.getLogger(ROOT_LOGGER_NAME) as Logger
override fun afterEach(extensionContext: ExtensionContext) {
listAppender.stop()
listAppender.list.clear()
logger.detachAppender(listAppender)
}
override fun beforeEach(extensionContext: ExtensionContext) {
logger.addAppender(listAppender)
listAppender.start()
}
val messages: List<String>
get() = listAppender.list.stream().map { e -> e.getMessage() }.collect(Collectors.toList())
val formattedMessages: List<String>
get() = listAppender.list.stream().map { e -> e.getFormattedMessage() }.collect(Collectors.toList())
}
Kotlin: Not enough information to infer type variable A
Not an error, but I have a feeling that it will fail in runtime:
private val logger: Logger = LoggerFactory.getLogger(ROOT_LOGGER_NAME) as Logger
Spring Boot comes with OutputCapture rule for JUnit 4 and OutputCaptureExtension for JUnit 5, that let you assert on text sent to standard output.
public class MyTest {
#Rule
public OutputCaptureRule output = new OutputCaptureRule();
#Test
public void test() {
// test code
assertThat(output).contains("ok");
}
}

Can we mock "CordaRPCops" in Cordapp for testing purpose?

Is it possible to mock CordaRPCops so as to execute a flow in project without creating a standalone node or in-memory node (like in a mock network) ? Kindly let me know.
I am also adding a link which I found informative regarding this from github issues QA
There is no specific class available mock CordaRPCops in the TestDSL. If you referring to mock some of the fuctionality of the node for cordapp testing, you should use the MockNode.
If you want to Mock CordaRPCops in the client app, you could use mockito to do so, example below:
Test:
#Test
public void testGetStateList(){
CordaRPCOps cordaRPCOps = Mockito.mock(CordaRPCOps.class);
Service service = new Service(cordaRPCOps);
Vault.Page<MyState> myStatePage =
new Vault.Page<>(Collections.EMPTY_LIST, Collections.EMPTY_LIST, 0L, Vault.StateStatus.ALL, Collections.EMPTY_LIST);
Mockito.when(cordaRPCOps.vaultQuery(MyState.class)).thenReturn(myStatePage);
service.getStateList();
}
Service:
public class Service {
CordaRPCOps cordaRPCOps;
public Service(CordaRPCOps cordaRPCOps) {
this.cordaRPCOps = cordaRPCOps;
}
public List<StateAndRef<MyState>> getStateList() {
return cordaRPCOps.vaultQuery(MyState.class).getStates();
}
}

Unable to generate the Spring rest docs using Cucumber

I am trying to test spring rest documentation for rest API for our services using spring cucumber jvm but end up with a null pointer exeception when I try to execute the scenario, as the framework is not able to intialize the Junit context.
Error Message:
java.lang.NullPointerException at
org.springframework.restdocs.ManualRestDocumentation.beforeO‌​peration(ManualRestD‌​ocumentation.java:90‌​) at
org.springframework.restdocs.JUnitRestDocumentation.beforeOp‌​eration(JUnitRestDoc‌​umentation.java:76)
Code:
private AppProperties props;
#Before("#rest") public void beforeScenario() {
JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation( "target/generated-snippets" );
System.out.println( "jUnitRestDocumentation " +restDocumentation );
spec = new RequestSpecBuilder().addFilter( documentationConfiguration( restDocumentation ) ).build();
System.out.println( "\n spec init .. " +restDocumentation );
}
Step definition code:
#Given("^create a rest document for VHR API$")
public void create_a_rest_document_for_VHR_API() throws Throwable {
estAssured.given( spec )
.accept( "application/json" )
.filter( document( "vhrdocument" ) ) .when()
.get( props.getVhrrequesturl() + "/vhrData/{vehicleID}", "5VW4T7AU0FM029999" ) .then().log().all();
}
You aren't using JUnitRestDocumentation as it's intended to be used. It's designed to be used as a JUnit rule which means it should be a public field annotated with #Rule:
#Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
Being a rule means that JUnit will automatically call restDocumentation for each test, allowing Spring REST Docs to set up and tear down the test-specific context. The NullPointerException is occurring because restDocumentation hasn't been called in this way and, therefore, the context hasn't been set up.
You haven't described how you're using Cucumber, but if you're using it's JUnit runner you should be able to fix the problem by declaring restDocumentation as a #Rule-annotated field as shown above. If you're not using its JUnit runner, you may need to use Spring REST Docs' ManualRestDocumentation instead. The Spring REST Docs reference documentation contains a section that describes how to set up your tests when you're not using JUnit.
I had the same problem because I had multiple test class inheriting the class, in which I declared the JUnitRestDocumentation instance. My mistake was that I declared the rule using the #Rule annotation. I should have used #ClassRule and declared the instance as static.
#ClassRule
public static JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
it happened with test SpockFramework, and i added to pom.xml:
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-junit4</artifactId>
<scope>test</scope>
</dependency>
I had the same symptoms when migrating from RestAssured 2.x to RestAssured 3.1.1.
The codebase had a way to setup RestAssured in order to avoid repetitive ceremony for every tests :
#Rule
public JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();
#Before
public void configure_rest_assured() {
RestAssured.port = springServerPort;
RestAssured.config = config().objectMapperConfig(
objectMapperConfig().jackson2ObjectMapperFactory((cls, charset) -> customObjectMapper)
)
...;
RestAssured.requestSpecification = new RequestSpecBuilder()
.addRequestSpecification(documentationConfiguration(docRule, ...))
...
.build();
}
This was working well, until I migrated to 3.x. The issue was that new RequestSpecBuilder() will append itself to the default static RestAssured.requestSpecification.
The first test passed, but when it finished the rule was disposed (the after part), when the second test started to ran, the Before method was chaining
the specification created for the first test (referencing the disposed rule used by the first test method)
the specification created for the second test (referencing the active rule for second test method)
And so on as new tests are ran.
But when the second test is run RestAssured invoke specification in order, e.g. the number 1, but since it was referencing a disposed rule (the beforeOperation was executed on a null context)
To fix that the code had to clear the previous specifications :
#Before
public void configure_rest_assured() {
RestAssured.port = springServerPort;
RestAssured.config = config().objectMapperConfig(
objectMapperConfig().jackson2ObjectMapperFactory((cls, charset) -> customObjectMapper)
)
...;
RestAssured.requestSpecification = null; // avoid the builder to acquire previous specs.
RestAssured.requestSpecification = new RequestSpecBuilder()
.addRequestSpecification(documentationConfiguration(docRule, ...))
...
.build();
}
For using cucumber-java-8 with spring rest docs and spring-security the following worked for me.
This is combining #AndyWilkison's answer from above but using the cucumber hooks instead of junit rules.
public class StepDefs implements En {
#Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
private ManualRestDocumentation restDocumentation = new ManualRestDocumentation();
public StepDefs() {
BeforeStep((Scenario scenario) -> {
restDocumentation.beforeTest(AuthenticationStepDefs.class, scenario.getName());
mockMvc = MockMvcBuilders.webAppContextSetup(context).apply(springSecurity()).apply(documentationConfiguration(restDocumentation)).build();
});
AfterStep((Scenario scenario) -> {
restDocumentation.afterTest();
});
When("create a rest document for VHR API", () -> {
MvcResult result = mockMvc.perform(/*
your normal call here
*/).
.andDo(document("documentation")).
.andReturn();
}
}
}

How to prevent developer call repository method from #Controller or scriptlet

I'm using spring to build Controller -> Service -> Repository architecture.
However, others developer can autowired repository in controller or anywhere.
I don't want others to violate the 3 layer architecture.
So, I using aspectj to check caller for Repository.
if caller is Service -> pass;
else throw exception.
#Aspect
public class ModelAdvice {
private Pattern pattern = Pattern.compile("^demo\\.services\\..*");
#Before("execution(* demo.repositories..*Repository.*(..))")
public void protectRepositories(JoinPoint joinPoint) {
StackTraceElement[] stElements = Thread.currentThread().getStackTrace();
for (StackTraceElement element : stElements) {
Matcher matcher = pattern.matcher(element.getClassName());
if (matcher.matches()) {
return;
}
}
throw new RuntimeException("security violation!");
}
}
It work, but ugly and may be slow.
Is spring have some elegant way to do this?

Resources