Skip to content

Make MvcResultAssert.getResponse() public #32643

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
odrotbohm opened this issue Apr 16, 2024 · 9 comments
Closed

Make MvcResultAssert.getResponse() public #32643

odrotbohm opened this issue Apr 16, 2024 · 9 comments
Labels
in: test Issues in the test module status: declined A suggestion or change that we don't feel we should currently apply

Comments

@odrotbohm
Copy link
Member

MockMvc allows returning the response that one defined expectations on as a subsequent operation, which allows writing assertions like this:

return mvc.perform(get("/").accept(…))
  .andExpect(status().isOk())
  .andReturn().getResponse();

I would appreciate it if we could return the response of an operation from a MvcResultAssert, too.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Apr 16, 2024
@jhoeller jhoeller added the in: test Issues in the test module label Apr 16, 2024
@snicoll
Copy link
Member

snicoll commented Apr 16, 2024

Shouldn’t you use satisfies for this?

@odrotbohm
Copy link
Member Author

I need to return the result from a method.

@snicoll
Copy link
Member

snicoll commented Apr 16, 2024

Ok. An assert object is not meant to expose anything. You can assign the result of perform and get the response from there. Would that work?

@odrotbohm
Copy link
Member Author

Yes, that works and is what I do as a workaround. I assume that other trying to migrate their existing assertion pipelines will run into this as well.

Furthermore, getResponse() is already present, but protected. So I wonder why it should be fine to call that method on the object returned from ….andExpect(…) but not the assertion object.

@snicoll
Copy link
Member

snicoll commented Apr 16, 2024

It doesn’t matter that the method already exists. As I’ve tried to explain, we’re following what AssertJ does and they don’t expose their internal state with a getter like that (and they have them protected just because the hierarchy needs access to it).

Mixing AssetJ with returning an element of the result and not willing to assign the result doesn’t look like a common case to me. But perhaps I am missing something.

@odrotbohm
Copy link
Member Author

odrotbohm commented Apr 16, 2024

We’re following what AssertJ does and they don’t expose their internal state with a getter like that (and they have them protected just because the hierarchy needs access to it).

Well, we're extending AssertJ. Which naturally means adding stuff to the thing that's extended, isn't it? So, AssertJ not doing something we do is by definition, isn't it? Furthermore, that internal state already is exposed on AssertableMvcResult. There's nothing to be hidden, really. What do we gain from asking developers to write boilerplate code in this particular case? That we differentiate what an AbstractAssert is allowed to expose VS. an AssertProvider?

Mixing AssertJ with returning an element of the result and not willing to assign the result doesn’t look like a common case to me.

Not willing sounds stubborn. I just think it would be nice to return the result of such an operation immediately, without having to capture some state initially solely to obtain the thing I want to return from it later. It's already possible on MockMvc: define the request, chain expectations, return an aspect of the result. I don't see how anything in AssertJ is deeming that problematic non-idiomatic.

Using the response of a request is pretty common, as soon as you move beyond one-line examples and have test methods that execute slightly more complex testing flows that span multiple requests. Find an example of that in Spring RESTBucks.

@snicoll
Copy link
Member

snicoll commented Apr 19, 2024

Well, we're extending AssertJ. Which naturally means adding stuff to the thing that's extended, isn't it?

Yes, just like any custom Assert, including the ones provided by AssertJ itself. The point I was trying to make is that we want the user experience to be natural and consistent with other Assert classes. And an Assert either returns SELF or a more dedicated assert instance based on an extracting function of some kind. It usually doesn't have a termination method that returns actual or some state of actual.

Furthermore, that internal state already is exposed on AssertableMvcResult

Again, that doesn't matter. And to be clear, I am not denying the use case here, just that it has to be fixed by making a method public, because it "is already present". I've already noticed a use case with async request where you want to first make a request and then get the response to trigger another perform. Your sample takes that to the next level with chain of processing that each take the previous response and contribute the one used by the next. I wonder if we shouldn't make that use case first class by providing a dedicated method. We'd need to hack a bit more to see how we'd name that though.

WDYT?

@snicoll snicoll added the status: waiting-for-feedback We need additional information before we can continue label Apr 19, 2024
@odrotbohm
Copy link
Member Author

In the end, I, personally, am more concerned about our users' ability to write boilerplate-free code. IMO, what is or is not deemed idiomatic should be of lower priority. Especially, as in this case, the absence of a certain style of method is equated with being non-idiomatic, which, I think, is not the same thing. But I've already argued that in a multitude of ways.

Find the translation of the Hamcrest-based definition of matchers to the AssertJ ones in Spring RESTBucks here. Note how, on multiple occasions (more here and here), this causes what could have been expressed in a single, fluent statement now has to be broken up into multiple expressions.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 23, 2024
@snicoll
Copy link
Member

snicoll commented Apr 24, 2024

Thanks for sharing the migration.

this causes what could have been expressed in a single, fluent statement now has to be broken up into multiple expressions.

I am sorry but I don't see how this has to be a must have. Doing so would mean you'd have to write something like return assertThat(mvc.perform(...) and that would read very strangely indeed.

I think you've done that by accident actually, calling result what is actually an assert object.

I am going to close this now, but I am keeping the use case of producing another request based on a previous response in mind as I've shared in my previous comment.

@snicoll snicoll closed this as not planned Won't fix, can't repro, duplicate, stale Apr 24, 2024
@snicoll snicoll added status: declined A suggestion or change that we don't feel we should currently apply and removed status: waiting-for-triage An issue we've not yet triaged or decided on status: feedback-provided Feedback has been provided labels Apr 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: test Issues in the test module status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

4 participants