Micronaut 嵌入式服务器与本地主机
Micronaut Embedded Server vs localhost
我刚开始使用 micronaut,我想了解使用本地主机和使用嵌入式服务器测试控制器之间的区别
例如
我有一个简单的控制器
@Controller("/hello")
public class HelloController {
@Get("/test")
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
和测试的class
@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();
}
在这两种情况下,您都在使用 EmbeddedServer
实现 - NettyHttpServer
。这是一个表示 Micronaut 服务器实现的抽象(在本例中为 NettyHttpServer
)。
主要区别在于 micronaut-test
提供了组件和注释,使编写 Micronaut HTTP 单元测试变得更加简单。在 micronaut-test
之前,您必须手动启动您的应用程序:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
那你就得准备一个HTTP客户端,例如:
HttpClient http = HttpClient.create(server.URL)
micronaut-test
将其简化为在测试 class 上添加 @MicronautTest
注释,然后运行器启动嵌入式服务器并初始化您可以注入的所有 bean。就像您在示例中注入 RxHttpClient
一样。
第二件值得一提的事情是 @MicronautTest
注释还允许您使用 @MockBean
注释来覆盖现有的 bean,其中包含您可以在测试级别定义的一些模拟。默认情况下,@MicronautTest
不模拟任何 bean,因此启动的应用程序反映了 1:1 应用程序的运行时环境。当您手动启动 EmbeddedServer
时会发生同样的事情——这只是启动常规 Micronaut 应用程序的一种编程方式。
所以结论很简单 - 如果您想在测试中编写更少的样板代码 classes,请使用 micronaut-test
及其所有注释以使测试更简单。没有它,你将不得不手动控制所有事情(启动 Micronaut 应用程序,从应用程序上下文中检索 beans 而不是使用 @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
注释,而 create/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
如果想访问它,但没有必要这样做。
我刚开始使用 micronaut,我想了解使用本地主机和使用嵌入式服务器测试控制器之间的区别
例如 我有一个简单的控制器
@Controller("/hello")
public class HelloController {
@Get("/test")
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
和测试的class
@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();
}
在这两种情况下,您都在使用 EmbeddedServer
实现 - NettyHttpServer
。这是一个表示 Micronaut 服务器实现的抽象(在本例中为 NettyHttpServer
)。
主要区别在于 micronaut-test
提供了组件和注释,使编写 Micronaut HTTP 单元测试变得更加简单。在 micronaut-test
之前,您必须手动启动您的应用程序:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
那你就得准备一个HTTP客户端,例如:
HttpClient http = HttpClient.create(server.URL)
micronaut-test
将其简化为在测试 class 上添加 @MicronautTest
注释,然后运行器启动嵌入式服务器并初始化您可以注入的所有 bean。就像您在示例中注入 RxHttpClient
一样。
第二件值得一提的事情是 @MicronautTest
注释还允许您使用 @MockBean
注释来覆盖现有的 bean,其中包含您可以在测试级别定义的一些模拟。默认情况下,@MicronautTest
不模拟任何 bean,因此启动的应用程序反映了 1:1 应用程序的运行时环境。当您手动启动 EmbeddedServer
时会发生同样的事情——这只是启动常规 Micronaut 应用程序的一种编程方式。
所以结论很简单 - 如果您想在测试中编写更少的样板代码 classes,请使用 micronaut-test
及其所有注释以使测试更简单。没有它,你将不得不手动控制所有事情(启动 Micronaut 应用程序,从应用程序上下文中检索 beans 而不是使用 @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
注释,而 create/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
如果想访问它,但没有必要这样做。