【问题标题】:Micronaut Embedded Server vs localhostMicronaut 嵌入式服务器与本地主机
【发布时间】:2019-07-09 12:39:48
【问题描述】:

我开始使用 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();

}

【问题讨论】:

    标签: java junit micronaut embedded-server


    【解决方案1】:

    在这两种情况下,您都在使用 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,但没有必要这样做。

    【讨论】:

      猜你喜欢
      • 2014-06-04
      • 2021-08-25
      • 2017-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-20
      • 2018-04-30
      相关资源
      最近更新 更多