Micronaut嵌入式服务器与本地主机

时间:2019-07-09 12:39:48

标签: java junit micronaut embedded-server

我开始使用micronaut,我想了解使用本地主机测试控制器和使用嵌入式服务器之间的区别

例如 我有一个简单的控制器

@Controller("/hello")
public class HelloController {

  @Get("/test")
  @Produces(MediaType.TEXT_PLAIN)
  public String index() {
    return "Hello World";
  }  
}

和经过测试的课程

@MicronautTest
public class HelloControllerTest {

  @Inject
  @Client("/hello")
  RxHttpClient helloClient;

  @Test
  public void testHello() {
    HttpRequest<String> request = HttpRequest.GET("/test");
    String body = helloClient.toBlocking().retrieve(request);

    assertNotNull(body);
    assertEquals("Hello World", body);
  }
}

我得到了日志:

14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Sending HTTP Request: GET /hello/test
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Chosen Server: localhost(51995)

但是,在哪种情况下,我们需要嵌入式服务器?为什么? 在哪里可以找到了解它的文档。我阅读了Micronaut的文档,但对我来说不清楚,实际上发生了什么,为什么? 像这个例子:

 @Test
  public void testIndex() throws Exception {

    EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);

    RxHttpClient client = server.getApplicationContext().createBean(RxHttpClient.class, server.getURL());

    assertEquals(HttpStatus.OK, client.toBlocking().exchange("/hello/status").status());
    server.stop();

}

1 个答案:

答案 0 :(得分:3)

在两种情况下,您都使用EmbeddedServer实现-NettyHttpServer。这是代表Micronaut服务器实现(在这种情况下为NettyHttpServer)的抽象。

主要区别在于micronaut-test提供了使编写Micronaut HTTP单元测试更加简单的组件和注释。在micronaut-test之前,您必须使用以下方法手动启动应用程序:

EmbeddedServer server = ApplicationContext.run(EmbeddedServer)

然后,您必须准备一个HTTP客户端,例如:

HttpClient http = HttpClient.create(server.URL)

micronaut-test使其简化为在测试类上添加@MicronautTest批注,运行程序启动嵌入式服务器并初始化您可以注入的所有bean。就像在示例中注入RxHttpClient一样。

第二点值得一提的是,@MicronautTest批注还允许您使用@MockBean批注覆盖可以在测试级别定义的模拟的现有bean。默认情况下,@MicronautTest不模拟任何bean,因此启动的应用程序反映了1:1应用程序的运行时环境。手动启动EmbeddedServer时会发生同样的事情-这只是启动常规Micronaut应用程序的编程方式。

因此,结论非常简单-如果您想在测试类中编写更少的样板代码,请使用micronaut-test及其所有注释来简化测试。没有它,您将必须手动控制所有事情(启动Micronaut应用程序,从应用程序上下文中检索bean而不是使用@Inject批注,等等。)

最后但并非最不重要的是,这是不使用micronaut-test编写的同一测试:

package com.github.wololock.micronaut.products

import io.micronaut.context.ApplicationContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

class ProductControllerSpec extends Specification {

  @Shared
  @AutoCleanup
  EmbeddedServer server = ApplicationContext.run(EmbeddedServer)

  @Shared
  @AutoCleanup
  HttpClient http = server.applicationContext.createBean(RxHttpClient, server.URL)


  def "should return PROD-001"() {
    when:
    Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)

    then:
    product.id == 'PROD-001'

    and:
    product.name == 'Micronaut in Action'

    and:
    product.price == 29.99
  }

  def "should support 404 response"() {
    when:
    http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))

    then:
    def e = thrown HttpClientResponseException
    e.status == HttpStatus.NOT_FOUND
  }
}

在这种情况下,我们不能使用@Inject注释,创建/注入bean的唯一方法是直接使用applicationContext对象。 (请记住,在这种情况下,RxHttpClient bean在上下文中不存在,我们必须创建它-在micronaut-test情况下,此bean是为我们预先准备的。)

这是使用micronaut-test简化测试的同一测试:

package com.github.wololock.micronaut.products

import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification

import javax.inject.Inject

@MicronautTest
class ProductControllerSpec extends Specification {

  @Inject
  @Client("/")
  HttpClient http

  def "should return PROD-001"() {
    when:
    Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)

    then:
    product.id == 'PROD-001'

    and:
    product.name == 'Micronaut in Action'

    and:
    product.price == 29.99
  }

  def "should support 404 response"() {
    when:
    http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))

    then:
    def e = thrown HttpClientResponseException
    e.status == HttpStatus.NOT_FOUND
  }
}

更少的样板代码,并且效果相同。如果想访问它,我们甚至可以@Inject EmbeddedServer embeddedServer,但没有必要。