Grails 2.4.4. We have many JSON / REST API endpoints, as shown below, but with much more code (NOTE: We cannot use RestfulController because we have SpringSecurity and they are incompatible)
eg.
class SessionController def sessionService static namespace = 'v1' static allowedMethods = [loginPlayer: "POST"] def loginPlayer() { def payload = request.JSON try { // Check params are there. if (payload.user == null) { render(status: 422, contentType: 'application/json') { [ 'result' : -1 'description': "missing params" ] return } def result = sessionService.loginPlayer( payload.user, payload.password ) if (result.returnCode == 0) { render(status: 200, contentType: 'application/json') { [ 'result' : 0 'authToken' : result.authToken etc.
We are currently testing them manually using SOAPUI. We desperately need automated integration tests that test the entire API to the end with respect to the database.
We tried this:
class SessionControllerIntegrationSpec extends IntegrationSpec { SessionController controller def setup() { } def cleanup() { } void "test login"() { controller = new SessionController() controller.request.contentType = 'application/json' controller.request.format = 'json' controller.response.format = 'json' when: controller.request.content = '{"user":"someuser","password":"somepass"}'.getBytes() def model = controller.loginPlayer() then: model != null } }
But it always returns null as a model.
Also tried:
class SessionControllerIntegrationSpec extends GroovyTestCase { : def sessionService : controller.sessionService = sessionService
In accordance with the instructions for transmission to test controllers with services "
But this did not help - the result is still null. Also, the GroovyTestCase extension means a return to claims.
Is that what we are trying to do is even possible?
We see that some people conduct integration testing by removing the external URLs of the local host, for example:
class ExampleWebAppSpecification extends Specification { def "Should return 200 & a message with the input appended"() { setup: def primerEndpoint = new RESTClient( 'http://localhost:8080/' ) when: def resp = primerEndpoint.get([ path: 'exampleendpoint', query : [ input : 'Get a hair cut' ]]) then: with(resp) { status == 200 contentType == "application/json" } with(resp.data) { payload == "Something really important: Get a hair cut" } } }
This is not much different than using jmeter or another tool to test a running server and has many dependencies.
Any tips or suggestions?
UPDATE 1:
found an example that does this
assert controller.response.getStatus() == 200
In the debugger, controller.response.getStatus () returns 405 (a status that our controller never returns), and controller.response.contentAsString returns "".
When we run tests in the debugger, the code of the controllers is never called. Thus, the problem may be that grails does not introduce a SessionController at all.
UPDATE 2
Having guessed that the problem is with the request methods, try adding this:
controller.request.requestMethod = HttpMethod.POST
However, this still spawns 405.
In the REST controller, we have the following:
static allowedMethods = [loginPlayer: "POST"]
If I comment on this, I get the expected response!
So, the problem is how to get the test to use POST (setting requestMethod doesn't seem to do this), or how to change the controller to receive GET if it is in test mode?
UPDATE 3 - SOLVED! Work code below:
class SessionControllerIntegrationSpec extends IntegrationSpec def sessionService
class SessionControllerIntegrationSpec extends IntegrationSpec { SessionController controller void "test login"() { controller = new SessionController() // must manually create controller.sessionService = sessionService // must manually inject controller.request.contentType = 'application/json' controller.request.format = 'json' controller.response.format = 'json' controller.request.requestMethod = HttpMethod.POST controller.request.method = 'POST' when: controller.request.content = '{"user":"someuser","password":"somepass"}'.getBytes() then: assert controller.response.getStatus() == 200 print "CONTENT: " + controller.response.contentAsString // now can use string search functions to check the JSON data returned.