grails / grails-core

The Grails Web Application Framework
http://grails.org
Apache License 2.0
2.79k stars 949 forks source link

Inject Micronaut Http client at integrationstests #11368

Open andersaaberg opened 5 years ago

andersaaberg commented 5 years ago

Thanks for reporting an issue for Grails framework, please review the task list below before submitting the issue. Your issue report will be closed if the issue is incomplete and the below tasks not completed.

NOTE: If you are unsure about something and the issue is more of a question a better place to ask questions is on Stack Overflow (http://stackoverflow.com/tags/grails) or Slack (http://slack-signup.grails.org). DO NOT use the issue tracker to ask questions.

Task List

Steps to Reproduce

When doing automatic integration testing in Micronaut, I can inject the embedded httpServer without specifying host nor port. This is very convenient as the port is randomised by default in tests.

Here is an example Spock testcase from Micronaut, where I have a HelloController that returns "Hello World":

    @Inject
    @Client('/') // <-- no need to specify port nor host
    RxHttpClient client

    void "call app"() {
        when:
        String reply = client.toBlocking().retrieve('/hello')

        then:
        reply == 'Hello World'
    }

With Micronaut HTTP client being introduced in Grails 4.0, it would be very nice if we could avoid having to specify the hostname and port for Micronaut HTTP client in Grails integrationtests as well.

Right now I am doing this to get the Micronaut HTTP client in my integrationtests in Grails:

    @LocalServerPort
    Integer localServerPort // random port in tests

    BlockingHttpClient httpClient

    def setup() {
        httpClient = httpClient ?: HttpClient.create(new URL("http://localhost:${localServerPort}")).toBlocking()
    }

It would be very nice if I could do like in Micronaut:

    @Inject
    @Client('/') // <-- no need to specify port nor host
    RxHttpClient client

Expected Behaviour

the http client should be injected without needing to specify port and host

Actual Behaviour

the http client does not get injected

Environment Information

Example Application

jeffscottbrown commented 5 years ago

Fyi.. In a test marked with @Integration, you can refer to the serverPort variable

jeffscottbrown commented 5 years ago

You can simplify your test a little by using an approach like this:

import grails.testing.mixin.integration.Integration
import grails.testing.spock.OnceBefore
import io.micronaut.http.client.HttpClient
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

@Integration
class GreetingSpec extends Specification {

    @Shared
    @AutoCleanup
    HttpClient client

    @OnceBefore
    void initClient() {
        client = HttpClient.create("http://localhost:$serverPort".toURL())
    }

    void 'test client'() {
        expect:
        client.toBlocking().retrieve('/hello/Jeff') == 'Hola Jeff'
    }

    void 'test client again'() {
        expect:
        client.toBlocking().retrieve('/goodbye/Jeff') == 'Adios Jeff'
    }
}
andersaaberg commented 5 years ago

Thanks for the improvements, @jeffbrown!

I am sure that Grails users would like to be able to save that one line of code by just injecting the Micronaut HTTP client like in Micronaut. Grails just has to create a Micronaut HTTP client bean and set the baseurl based on server host + port. It fits well with Grails convention over configuration.