Another point.
On a controller or endpoint layer we operate with requests and responses. Hence we have a response body in our testing scenario that is a plain text. Text is transferred via network, not information about data type.
So any manipulations with data type of response body on tests side looks strange for me.
Software engineer with over 10 years experience in different technology stacks, architecting, developing, CI/CD and leading teams. Currently working with Java, Node.JS and Serverless
"Are you sure we can "unit test" a controller" - yes, you can.
"..any manipulations with data type of response body on tests side looks strange for me." - kind of true, but the thing is that because you are using MockMvc and not really the runtime config you get different JSON parser by default anyway. You can get as close as possible to your runtime config through additional hacks which I described in the post. This is a question not whether you can unit test controllers but whether you should. Integration tests have its own pros & cons.
1 Within unit tests we operate only with methods of a class. Within components tests we can operate with several classes.
But we don't know anything about controllers, endpoints, threads, timers, file system in unit (and component) tests.
We know about them in integration tests.
Remember last year where we had to fight with crazy "unit tests" that run for ages :-) Lack of separation between tests was the major issue I saw in all products.
Pure unit and component tests run super fast since they operate only with RAM.
2 Let's identify what we want to test ignoring how we name this test (i.e. integration or unit test).
If we test an endpoint (web service according to target post), probably we want to verify how this endpoint reacts to incoming requests by checking what is returned as a response.
Since response body is plain text in our case this is what we want to check.
But we convert this body to some format by adding some workarounds to achieve that and just to finally verify the body itself. Why not to verify the body as is without redundant conversion to some format? :-)
So we could replace .andExpect(jsonPath("$.value", is(ExampleController.VALUE_DOUBLE_FAIL)));
with .andExpect(jsonPath("$.value",
is(ExampleController.VALUE_BIG_DECIMAL_FAIL.toString())));
and remove a workaround with JSON parser. Please note that this is a pseudo code (i.e. comparing string values) but the idea should be clear.
In this case we don't loose anything since we verify the only thing we care - response body.
Software engineer with over 10 years experience in different technology stacks, architecting, developing, CI/CD and leading teams. Currently working with Java, Node.JS and Serverless
I'm talking about unit tests as such that do not require whole spring context to start.
That won't work because of the library limitation. I see your point but that's how the asserts works. If you try to compare "to-string" expected value with the decimal value from controller they will fail. The library would need to convert the decimals somewhow to string before the assert and this would also be a smelly hack :) In current state you'll get:
java.lang.AssertionError: JSON path "$.value"
Expected: is "0.071854545056424"
but: was <0.071854545056424>
Expected :is "0.071854545056424"
Actual :<0.071854545056424>
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Are you sure we can "unit test" a controller?
Another point.
On a controller or endpoint layer we operate with requests and responses. Hence we have a response body in our testing scenario that is a plain text. Text is transferred via network, not information about data type.
So any manipulations with data type of response body on tests side looks strange for me.
"Are you sure we can "unit test" a controller" - yes, you can.
"..any manipulations with data type of response body on tests side looks strange for me." - kind of true, but the thing is that because you are using MockMvc and not really the runtime config you get different JSON parser by default anyway. You can get as close as possible to your runtime config through additional hacks which I described in the post. This is a question not whether you can unit test controllers but whether you should. Integration tests have its own pros & cons.
1 Within unit tests we operate only with methods of a class. Within components tests we can operate with several classes.
But we don't know anything about controllers, endpoints, threads, timers, file system in unit (and component) tests.
We know about them in integration tests.
Remember last year where we had to fight with crazy "unit tests" that run for ages :-) Lack of separation between tests was the major issue I saw in all products.
Pure unit and component tests run super fast since they operate only with RAM.
2 Let's identify what we want to test ignoring how we name this test (i.e. integration or unit test).
If we test an endpoint (web service according to target post), probably we want to verify how this endpoint reacts to incoming requests by checking what is returned as a response.
Since response body is plain text in our case this is what we want to check.
But we convert this body to some format by adding some workarounds to achieve that and just to finally verify the body itself. Why not to verify the body as is without redundant conversion to some format? :-)
So we could replace
.andExpect(jsonPath("$.value", is(ExampleController.VALUE_DOUBLE_FAIL)));
with
.andExpect(jsonPath("$.value",
is(ExampleController.VALUE_BIG_DECIMAL_FAIL.toString())));
and remove a workaround with JSON parser. Please note that this is a pseudo code (i.e. comparing string values) but the idea should be clear.
In this case we don't loose anything since we verify the only thing we care - response body.
I'm talking about unit tests as such that do not require whole spring context to start.
That won't work because of the library limitation. I see your point but that's how the asserts works. If you try to compare "to-string" expected value with the decimal value from controller they will fail. The library would need to convert the decimals somewhow to string before the assert and this would also be a smelly hack :) In current state you'll get: