简体   繁体   中英

Cannot able to Mock my service's methods in Spring Reactive

I am trying to use Spring reactive to develop a chat application. Basically, I have a CommentRestController which has postComment , and list methods. - I've deleted the list method and some other unnecessary and unrelated methods, since I am not focused on them right now - Here it is;

@RestController
@RequiredArgsConstructor
@RequestMapping("/chat/comment")
public class CommentRestController {

private final CommentService commentService;
private final ChannelService channelService;

@PostMapping("/add")
public Mono<AddCommentResponse> postComment(@Valid @RequestBody Comment comment, ServerWebExchange serverWebExchange) {
    String userName = serverWebExchange.getAttribute("username");

    return commentService.save(userName, comment);
}
}

Now, I am trying to write this Controller's Documentation test. The problem which I've encountered is, I am not able to mock my commentService's save method. Its actually mocking the instance but not the method.

Here is my Documentation test class.

@RunWith(SpringRunner.class)
@SpringBootTest(properties = {"token-validation-service.url = http://localhost:8080/token-validation-service/", "profanity.similarity = 0.9"})
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
public class CommentRestControllerDocumentationTest {

@Rule
public final JUnitRestDocumentation restDocumentation = new JUnitRestDocumentation();

private WebTestClient webTestClient;

@Autowired
private CommentRestController commentRestController;

@MockBean
CommentService commentService;

@MockBean
ChannelService channelService;

@MockBean
ServerWebExchange serverWebExchange;

@MockBean
TokenValidationServiceClient tokenValidationServiceClient;

@MockBean
OperationResult operationResult;

@MockBean
AddCommentResponse addCommentResponse;

private RequestHeadersSnippet requestHeaderSnippet = requestHeaders(headerWithName("X-Auth-Token").description("Authentication Access Token"));

private FieldDescriptor responseReturnCode = fieldWithPath("meta.return_code").description("Operation return code");
private FieldDescriptor responseMessage = fieldWithPath("meta.message").description("Operation message");

private FieldDescriptor idField = fieldWithPath("id").description("id of the comment");
private FieldDescriptor authorField = fieldWithPath("author").description("Author of the comment");
private FieldDescriptor commentField = fieldWithPath("text").description("Comment itself");
private FieldDescriptor channelIdField = fieldWithPath("channelId").description("Channel Id of the comment");
private FieldDescriptor timestampField = fieldWithPath("timestamp").description("Timestamp of the comment");
private FieldDescriptor usernameField = fieldWithPath("username").description("Username of the comment, to check who commented");
private FieldDescriptor isBadField = fieldWithPath("isBad").description("Profanity check for comment");


@Before
public void setUp() {
    webTestClient = WebTestClient.bindToController(commentRestController)
            .configureClient()
            .filter(documentationConfiguration(restDocumentation))
            .build();
}

@Test
@WithMockUser
public void postComment() throws Exception {

    String stubName = "postComment";

    Comment comment = new Comment();
    comment.setId("1");
    comment.setAuthor("orcun");
    comment.setChannelId("123");
    comment.setText("This is a test method");
    comment.setIsBad(false);
    comment.setTimestamp("1479249799770");
    comment.setUsername("5332109939");

    operationResult.setReturnCode(ChatServiceConstants.SUCCESS_CODE);
    operationResult.setMessage(ChatServiceConstants.SUCCESS_MESSAGE);

    addCommentResponse.setOperationResult(operationResult);
    when(serverWebExchange.getAttribute("username")).thenReturn("5332109939");
    String userName = serverWebExchange.getAttribute("username");

    when(commentService.save(userName, comment)).thenReturn(Mono.just(addCommentResponse));

    webTestClient.post().uri("/chat/comment/add")
            .header("X-Auth-Token", "8811-1113")
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromObject(comment))
            .exchange()
            .expectStatus().isOk()
            .expectBody()
            .consumeWith(document(stubName,
                    requestFields(idField, authorField, commentField, timestampField,
                            channelIdField, usernameField, isBadField),
                    responseFields(responseReturnCode, responseMessage)));
}
}

When I run this, I am seeing an error which states response body is empty. Here it is:

org.springframework.restdocs.snippet.SnippetException: Cannot document response fields as the response body is empty

at org.springframework.restdocs.payload.AbstractFieldsSnippet.verifyContent(AbstractFieldsSnippet.java:201)
at org.springframework.restdocs.payload.AbstractFieldsSnippet.createModel(AbstractFieldsSnippet.java:157)
at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:83)
at org.springframework.restdocs.generate.RestDocumentationGenerator.handle(RestDocumentationGenerator.java:206)
at org.springframework.restdocs.webtestclient.WebTestClientRestDocumentation.lambda$document$0(WebTestClientRestDocumentation.java:81)
at org.springframework.test.web.reactive.server.DefaultWebTestClient$DefaultBodyContentSpec.lambda$consumeWith$2(DefaultWebTestClient.java:496)
at org.springframework.test.web.reactive.server.ExchangeResult.assertWithDiagnostics(ExchangeResult.java:194)
at org.springframework.test.web.reactive.server.DefaultWebTestClient$DefaultBodyContentSpec.consumeWith(DefaultWebTestClient.java:496)
at com.turkcell.tvplus.tvpluschat.rest.CommentRestControllerDocumentationTest.postComment(CommentRestControllerDocumentationTest.java:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.restdocs.JUnitRestDocumentation$1.evaluate(JUnitRestDocumentation.java:63)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

When I open the path of target/generated-snippets , I am seeing that docs of the method are generated but response-fields.adoc is empty.

I walked over the code with a debug session, and I realized that I am not able to mock my commentService.save() method.

Any help will be greatly appreciated. Thanks in advance.

The problem is reactive development requires time-unrelated apps. That's why applications like twitter or chats are using this. In most of the cases like mine, expected contents couldn't even got back to where it belongs.

That's why writing a unit test to a reactive project a bit harder that you think.

Answer to my question above is nothnig specific more than this. Hope this helps to people.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM