В обоих случаях вы используете 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
к тестовому классу, и бегун запускает встроенный сервер и инициализирует все компоненты, которые вы можете добавить. Как и в случае с инъекцией RxHttpClient
в вашем примере.
Второе, на что стоит обратить внимание, это то, что аннотация @MicronautTest
также позволяет вам использовать аннотацию @MockBean
для переопределения существующего компонента с помощью некоторого макета, который вы можете определить на уровне теста. По умолчанию @MicronautTest
не проверяет какие-либо компоненты, поэтому приложение, которое запускается, отражает среду выполнения приложения 1: 1. То же самое происходит, когда вы запускаете EmbeddedServer
вручную - это просто программный способ запуска обычного приложения Micronaut.
Таким образом, вывод довольно прост - если вы хотите писать меньше шаблонного кода в своих тестовых классах, используйте micronaut-test
со всеми его аннотациями, чтобы сделать ваши тесты проще. Без этого вам придется вручную управлять всеми вещами (запускать приложение Micronaut, извлекать компоненты из контекста приложения вместо использования аннотации @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
не существует в контексте, и мы должны его создать - в случае micronaut-test
этот компонент подготовлен для нас заранее.)
А вот тот же тест, который использует 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
, если бы хотели получить к нему доступ, но в этом нет необходимости.