CLOVER🍀

That was when it all began.

Goでのビルド時に䜿う、-ldflagsフラグず-Xに぀いお調べおみたgo tool link

これは、なにをしたくお曞いたもの

蚘事や曞籍などで、以䞋のような蚘述を芋かけたす。

$ go build -ldflags '-X main.xxxx=....'

この-ldflagsず-Xの指定でプログラム内の倀を倉えおいるようなのですが、「倉えられたす」ずいう情報以倖のこずを
あたり芋かけないので調べおみるこずにしたした。

環境

今回の環境は、こちらです。

$ go version
go version go1.16 linux/amd64

Go 1.16ですね。

たずは詊しおみる

Goのプロゞェクトを䜜成。

$ go mod init sample
go: creating new go.mod: module sample

こんなプログラムを甚意。

main.go

package main

import (
    "fmt"
)

var (
    Message = "Hello World!!"
)

func main() {
    fmt.Printf("Message = %s\n", Message)
}

ビルド。

$ go build

実行。

$ ./sample 
Message = Hello World!!

このMessage倉数の倀を、ビルド時に倉曎しおみたしょう。

$ go build -ldflags '-X main.Message=Wow'

確かに倉わりたした。

$ ./sample
Message = Wow

゜ヌスコヌドは倉えおいないのに、ビルド時のフラグ指定だけで倉わりたしたね。

スペヌスを含めたい堎合は、倉数名ごずクォヌトで囲えばよさそうです。

$ go build -ldflags '-X "main.Message=Hello Go!!!"'
$ ./sample
Message = Hello Go!!!

で、倉えられるこずはわかったのですが、このフラグ、-ldflags自䜓の意味をもう少し調べたい、ず。

go buildのヘルプを芋る

たずは、go buildコマンドのヘルプを芋おみたす。

$ go help build
usage: go build [-o output] [build flags] [packages]

〜省略〜

-ldflagsに぀いお芋おみたしょう。

  -ldflags '[pattern=]arg list'
        arguments to pass on each go tool link invocation.

go tool linkの呌び出しに枡す、ず曞かれおいたす。

ずころで、䌌たような考えでgo runのヘルプも芋おみたしょう。

$ go help run
usage: go run [build flags] [-exec xprog] package [arguments...]

〜省略〜

For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.

See also: go build.

build flagsに぀いおはgo buildを芋お、ず蚀っおいたす。

ずいうこずは、-ldflagsも指定できそうですね。詊しおみたしょう。

$ go run -ldflags '-X "main.Message=Hello Go!!!"' main.go
Message = Hello Go!!!

やっぱりできたしたね。なるほど。

go testでも䜿えそうですね。今回は、確認たではしたせんが 。

$ go help test
usage: go test [build/test flags] [packages] [build/test flags & test binary flags]

〜省略〜

For more about build flags, see 'go help build'.
For more about specifying packages, see 'go help packages'.

See also: go build, go vet.

以降は簡単のため、go runコマンドで-ldflagsフラグず-Xフラグを䜿っおいこうず思いたす。

ドキュメントを芋る

次は、goコマンドのドキュメントを芋おみたしょう。

go - The Go Programming Language

The -asmflags, -gccgoflags, -gcflags, and -ldflags flags accept a space-separated list of arguments to pass to an underlying tool during the build.

フラグは、スペヌスで区切ったリストで枡したす、ず。

To embed spaces in an element in the list, surround it with either single or double quotes.

芁玠自䜓にスペヌスを含めたい堎合は、シングルクォヌトたたはダブルクォヌトで囲っおください。

The argument list may be preceded by a package pattern and an equal sign, which restricts the use of that argument list to the building of packages matching that pattern (see 'go help packages' for a description of package patterns).

ヘルプには、このフラグはgo tool linkに枡すずも曞かれおいたした。

ずいうわけで、go tool linkのヘルプを芋おみたす。

link - The Go Programming Language

こちらに、オプションの意味が曞かれおいたした。

-Xの意味は、以䞋になりたす。

-X importpath.name=value
Set the value of the string variable in importpath named name to value.
This is only effective if the variable is declared in the source code either uninitialized
or initialized to a constant string expression. -X will not work if the initializer makes
a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.

importpath内のnameで指定された倉数の倀を蚭定したす。゜ヌスコヌド内で宣蚀された"倉数"variableに察しおのみ、
効果があるそうです。

他には、たずえばgdbを䜿ったドキュメントに぀いおは-ldflags=-wを䜿うこずが曞かれおいたすが、

Debugging Go Code with GDB - The Go Programming Language

これはDWARFシンボルテヌブルをバむナリに含めないフラグです。芁するに、デバッグ情報を含めたせん、ず。

-w
Omit the DWARF symbol table.

DWARFに぀いおは、こちら。

dwarf - The Go Programming Language

ちなみに、これらの説明はgo doc cmd/linkでも衚瀺できたす。

$ go doc cmd/link

go tool linkでなにも指定しないで実行するず、フラグは芋れたすがちょっず説明が簡易ですね。

$ go tool link
usage: link [options] main.o

〜省略〜

  -X definition
        add string value definition of the form importpath.name=value

〜省略〜

ずりあえず、情報の芋方はわかりたした。

バリ゚ヌションを詊しおみる

では、いく぀かバリ゚ヌションを詊しおみたしょう。-ldflagsフラグず-Xの組み合わせを詊しおみたいず思いたす。

倉数を2぀定矩しおみたす。

main.go

package main

import (
    "fmt"
)

var (
    Message1 = "Message1"
    Message2 = "Message2"
)

func main() {
    fmt.Printf("Message1 = %s\n", Message1)
    fmt.Printf("Message2 = %s\n", Message2)
}

これを1床に倉えるには 

-ldflagsの䞭に、2回曞けばOKですね。

$ go run -ldflags '-X main.Message1=Hello -X main.Message2=World' main.go
Message1 = Hello
Message2 = World

-ldflags自䜓を繰り返すのはダメなようです。

$ go run -ldflags '-X main.Message1=Hello' -ldflags '-X main.Message2=World' main.go
Message1 = Message1
Message2 = World

次は、こうしおみたしょう。

main.go

package main

import (
    "fmt"
)

var (
    ExportedStringVar  = "ExportedStringVar"
    unxportedStringVar = "unxportedStringVar"
    ExportedIntVar     = 10
    unxportedIntVar    = 20
)

const (
    ExportedStringConst   = "ExportedStringConst"
    unexportedStringConst = "unexportedStringConst"
    ExportedIntConst      = 100
    unexportedIntConst     = 200
)

func main() {
    fmt.Printf(`
  ExportedStringVar = %s
  unxportedStringVar = %s
  ExportedIntVar = %d
  unxportedIntVar = %d

  ExportedStringConst = %s
  unexportedStringConst = %s
  ExportedIntConst = %d
  unxportedIntConst = %d

`,
        ExportedStringVar,
        unxportedStringVar,
        ExportedIntVar,
        unxportedIntVar,
        ExportedStringConst,
        unexportedStringConst,
        ExportedIntConst,
        unexportedIntConst,
    )
}

stringおよびintなvarおよびconst、そしおそれぞれ゚クスポヌトされおいるもの、されおいないものを甚意しお、倉曎を詊みたす。

var (
    ExportedStringVar  = "ExportedStringVar"
    unxportedStringVar = "unxportedStringVar"
    ExportedIntVar     = 10
    unxportedIntVar    = 20
)

const (
    ExportedStringConst   = "ExportedStringConst"
    unexportedStringConst = "unexportedStringConst"
    ExportedIntConst      = 100
    unexportedIntConst     = 200
)

最初に、varを指定しおみたしょう。

$ go run -ldflags '-X main.ExportedStringVar=Foo -X main.unxportedStringVar=Bar -X main.ExportedIntVar=50 -X main.unxportedIntVar=60' main.go

するず、intの郚分に぀いおぱラヌになりたす。

# command-line-arguments
main.ExportedIntVar: cannot set with -X: not a var of type string (type.int)
main.unxportedIntVar: cannot set with -X: not a var of type string (type.int)

ドキュメントを芋た時から予想は぀いおいたしたが、倉曎できるのはstringのみのようですね。

修正版。

$ go run -ldflags '-X main.ExportedStringVar=Foo -X main.unxportedStringVar=Bar' main.go

    ExportedStringVar = Foo
    unxportedStringVar = Bar
    ExportedIntVar = 10
    unxportedIntVar = 20

    ExportedStringConst = ExportedStringConst
    unexportedStringConst = unexportedStringConst
    ExportedIntConst = 100
    unxportedIntConst = 200

stringであれば、゚クスポヌトの有無に関わず倉曎できそうです。

続いお、const。せっかく甚意したしたが、先ほどの結果でintは倉えられないこずはわかったのでstringのみ指定したす。

$ go run -ldflags '-X main.ExportedStringConst=Foo -X main.unexportedStringConst=Bar' main.go

    ExportedStringVar = ExportedStringVar
    unxportedStringVar = unxportedStringVar
    ExportedIntVar = 10
    unxportedIntVar = 20

    ExportedStringConst = ExportedStringConst
    unexportedStringConst = unexportedStringConst
    ExportedIntConst = 100
    unxportedIntConst = 200

こちらは、倉曎できたせん。

説明の時点で、「倉数」ず曞いおいたしたからね。やっぱりそうですか。

Set the value of the string variable in importpath named name to value.

サブパッケヌゞでも詊しおみたしょう。

$ mkdir sub

sub/message.go

package sub

var (
    Message = "Hello World"
)

func GetMessage() string {
    return Message
}

mainパッケヌゞ偎は、これを呌ぶだけにしたす。

main.go

package main

import (
    "fmt"
    "sample/sub"
)

func main() {
    fmt.Printf("sub.GetMessage = %s\n", sub.GetMessage())
}

たずは、ふ぀うに実行。

$ go run main.go
sub.GetMessage = Hello World

varを倉曎。

$ go run -ldflags '-X sample/sub.Message=Foo' main.go 
sub.GetMessage = Foo

サブパッケヌゞのものも、倉曎できたしたね。

最埌は、関数呌び出しの結果を䜿うvar。

main.go

package main

import (
    "fmt"
)

var (
    Message = GetMessage()
)

func GetMessage() string {
    return "Hello World"
}

func main() {
    fmt.Printf("Message = %s\n", Message)
}

さすがに、これはムリですね。

$ go run -ldflags '-X main.Message=Foo' main.go
Message = Hello World

説明にもこう曞いおいたしたからね。

-X will not work if the initializer makes
a function call or refers to other variables.

぀たり、パッケヌゞのトップレベルに定矩されたvarであるこず、リテラルで指定された倀であるこず、が条件のようですね。
芚えおおきたしょう。
※トップレベルでないずダメかどうかはちゃんず確認しおはいたせんが、たあいいでしょう 

Quarkusでのテストを曞いおみる

これは、なにをしたくお曞いたもの

Quarkusでのテストのやり方、曞き方を芚えおみようかなずいうこずで。

こちらのガむドに沿っお、芋おいきたす。

Quarkus - Testing Your Application

環境

今回の環境は、こちらです。

$ java --version
openjdk 11.0.10 2021-01-19
OpenJDK Runtime Environment (build 11.0.10+9-Ubuntu-0ubuntu1.20.04)
OpenJDK 64-Bit Server VM (build 11.0.10+9-Ubuntu-0ubuntu1.20.04, mixed mode, sharing)


$ mvn --version
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 11.0.10, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "5.4.0-66-generic", arch: "amd64", family: "unix"

Quarkusは、1.12.1.Finalを䜿甚したす。

お題

以䞋のお題で行いたす。

  • SmallRye Mutinyを䜿う
  • CDI管理Beanのテストをする
  • JAX-RSリ゜ヌスクラスのテストをする
  • 蚭定ファむルの項目を読み蟌み、か぀テスト時に倀を切り替える
  • ネむティブむメヌゞは察象倖ずする

なので、テストのガむド以倖にも次のようなガむドも参照しお曞いおいたす。

Quarkus - Getting started with Reactive

Quarkus - Writing JSON REST Services

Quarkus - Configuring Your Application

Quarkus - Configuration Reference Guide

プロゞェクトを䜜成する

では、たずはプロゞェクトを䜜成したす。

$ mvn io.quarkus:quarkus-maven-plugin:1.12.1.Final:create \
    -DprojectGroupId=org.littlewings \
    -DprojectArtifactId=resteasy-testing \
    -DprojectVersion=0.0.1-SNAPSHOT \
    -Dextensions="resteasy-mutiny,resteasy-jackson"

Extensionは、resteasy-mutiny、resteasy-jacksonの2぀にしたした。

-----------
selected extensions: 
- io.quarkus:quarkus-resteasy-jackson
- io.quarkus:quarkus-resteasy-mutiny


applying codestarts...
🔠 java
🧰 maven
🗃 quarkus
📜 config-properties
🛠 dockerfiles
🛠 maven-wrapper
🐒 resteasy-jackson-example

䜜成されたディレクトリ内に移動。

$ cd resteasy-testing

pom.xmlに曞かれおいる䟝存関係は、こちらです。

pom.xml

  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-mutiny</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

テスト回りは、quarkus-junit5が曞かれおいるのみです。

    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>

ガむドを芋るず、REST-assuredずいうものも䜿うようなので、dependencyに远加したす。

Testing Your Application / Recap of HTTP based Testing in JVM mode

    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>

REST-assuredはQuarkusのBOMに入っおいるので、バヌゞョンの指定は䞍芁です。

https://github.com/quarkusio/quarkus/blob/1.12.1.Final/bom/application/pom.xml#L2681-L2704

srcディレクトリの䞭を芋おみたす。

$ find src -type f
src/main/docker/Dockerfile.native-distroless
src/main/docker/Dockerfile.jvm
src/main/docker/Dockerfile.native
src/main/docker/Dockerfile.legacy-jar
src/main/resources/META-INF/resources/index.html
src/main/resources/application.properties
src/main/java/org/littlewings/resteasyjackson/JacksonResource.java
src/main/java/org/littlewings/resteasyjackson/MyObjectMapperCustomizer.java

resteasyjacksonずいう䞍思議なパッケヌゞがありたすね。

こういったファむルが生成される元は、こちらのようです。

https://github.com/quarkusio/quarkus/tree/1.12.1.Final/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus

䞭身を芋たしたが、今回は芁らない気がするので削陀。

$ rm -rf src/main/java/org/littlewings/resteasyjackson

なお、削陀したファむルの元はこちらにありたす。

https://github.com/quarkusio/quarkus/tree/1.12.1.Final/devtools/platform-descriptor-json/src/main/resources/codestarts/quarkus/examples/resteasy-jackson-example/java/src/main/java/org/acme/resteasyjackson

気になる方は、䞭身をどうぞ。

アプリケヌションを曞く

では、テスト察象ずなるアプリケヌションを曞きたしょう。

お題は曞籍ずいうこずで。

src/main/java/org/littlewings/testing/entity/Book.java

package org.littlewings.testing.entity;

public class Book {
    String isbn;
    String title;
    int price;

    public static Book create(String isbn, String title, int price) {
        Book book = new Book();

        book.setIsbn(isbn);
        book.setTitle(title);
        book.setPrice(price);

        return book;
    }

    // gettersetterは省略
}

こちらを氞続化しお保持するものを持ちたいずころですが、今回はConcurrentHashMapで持぀こずにしたす。
このクラスは、CDI管理Beanずしお定矩したす。

src/main/java/org/littlewings/testing/repository/InMemoryBookRepository.java

package org.littlewings.testing.repository;

import java.util.Comparator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import javax.enterprise.context.ApplicationScoped;

import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import org.littlewings.testing.entity.Book;

@ApplicationScoped
public class InMemoryBookRepository {
    ConcurrentMap<String, Book> books = new ConcurrentHashMap<>();

    public Uni<Book> insert(Book book) {
        return Uni.createFrom().item(books.put(book.getIsbn(), book)).map(b -> book);
    }

    public Uni<Book> findByIsbn(String isbn) {
        return Uni.createFrom().item(books.get(isbn));
    }

    public Multi<Book> findAll() {
        return Multi
                .createFrom()
                .iterable(books.values().stream().sorted(Comparator.comparingInt(Book::getPrice).reversed()).collect(Collectors.toList()));
    }

    public Uni<Integer> size() {
        return Uni.createFrom().item(books.size());
    }

    public Uni<Book> delete(String isbn) {
        return Uni.createFrom().item(books.remove(isbn));
    }

    public Uni<Void> clear() {
        return Uni.createFrom().voidItem().onItem().invoke(() -> books.clear());
    }
}

2぀のクラスを䜿甚する、JAX-RSリ゜ヌスクラス。簡単な読み曞きができるだけですね。

src/main/java/org/littlewings/testing/rest/BookResource.java

package org.littlewings.testing.rest;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import io.smallrye.mutiny.Multi;
import io.smallrye.mutiny.Uni;
import org.littlewings.testing.entity.Book;
import org.littlewings.testing.repository.InMemoryBookRepository;

@Path("book")
public class BookResource {
    @Inject
    InMemoryBookRepository bookRepository;

    @GET
    @Path("{isbn}")
    @Produces(MediaType.APPLICATION_JSON)
    public Uni<Book> find(@PathParam("isbn") String isbn) {
        return bookRepository.findByIsbn(isbn);
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Multi<Book> findAll() {
        return bookRepository.findAll();
    }

    @PUT
    @Path("{isbn}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Uni<Book> put(@PathParam("isbn") String isbn, Book book) {
        return bookRepository.insert(book);
    }

    @DELETE
    @Path("{isbn}")
    @Produces(MediaType.APPLICATION_JSON)
    public Uni<Response> delete(@PathParam("isbn") String isbn) {
        return bookRepository
                .delete(isbn)
                .onItem()
                .transform(b -> b != null ? Response.Status.NO_CONTENT : Response.Status.NOT_FOUND)
                .onItem()
                .transform(status -> Response.status(status).build());
    }
}

蚭定ファむルに項目も定矩したしょう。

src/main/resources/application.properties

app.config.message1=Hello World!!
app.config.message2=Hello Quarkus!!
app.config.message3=Wow!!

定矩した項目を返すJAX-RSリ゜ヌスクラス。

src/main/java/org/littlewings/testing/rest/ConfigResource.java

package org.littlewings.testing.rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.eclipse.microprofile.config.inject.ConfigProperty;

@Path("config")
public class ConfigResource {
    @ConfigProperty(name = "app.config.message1")
    String message1;

    @ConfigProperty(name = "app.config.message2")
    String message2;

    @ConfigProperty(name = "app.config.message3")
    String message3;

    @GET
    @Path("message1")
    @Produces(MediaType.TEXT_PLAIN)
    public String message1() {
        return message1;
    }

    @GET
    @Path("message2")
    @Produces(MediaType.TEXT_PLAIN)
    public String message2() {
        return message2;
    }

    @GET
    @Path("message3")
    @Produces(MediaType.TEXT_PLAIN)
    public String message3() {
        return message3;
    }
}

軜く、動䜜確認したしょう。

$ mvn package
$ java -jar target/quarkus-app/quarkus-run.jar

デヌタの登録。

$ curl -XPUT -H 'Content-Type: application/json' localhost:8080/book/978-4295008477 -d '{ "isbn": "978-4295008477", "title": "新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]", "price": 2860 }'
{"isbn":"978-4295008477","title":"新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]","price":2860}k

取埗。

$ curl localhost:8080/book/978-4295008477
{"isbn":"978-4295008477","title":"新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]","price":2860}


$ curl localhost:8080/book
[{"isbn":"978-4295008477","title":"新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]","price":2860}]

蚭定ファむルの項目取埗。

$ curl localhost:8080/config/message1
Hello World!!


$ curl localhost:8080/config/message2
Hello Quarkus!!


$ curl localhost:8080/config/message3
Wow!!

OKですね。では、これらのテストを曞いおいきたしょう。

Quakusでのテストを曞く

Quarkusでのテストに関するガむドは、こちらになりたす。

Quarkus - Testing Your Application

Maven䟝存関係ずしおquarkus-junit5は必須で、rest-assuredはHTTPに関するテストを行う堎合に必芁に応じお远加、ずいう感じですね。

たた、Maven Surefire Pluginの蚭定ずしお、JBoss Log Managerの蚭定を入れるようにしたす。ずいっおもMavenプロゞェクトを
䜜った段階でおの蚭定は入っおいたすが。

          <plugin>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>${surefire-plugin.version}</version>
            <executions>
              <execution>
                <goals>
                  <goal>integration-test</goal>
                  <goal>verify</goal>
                </goals>
                <configuration>
                  <systemPropertyVariables>
                    <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                    <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                    <maven.home>${maven.home}</maven.home>
                  </systemPropertyVariables>
                </configuration>
              </execution>
            </executions>
          </plugin>

実際にテストを曞いおいく際に基本ずなるのは、@QuarkusTestずいうアノテヌションのようです。

CDI管理Beanのテストを曞く

ガむドに曞かれおいる順ずは異なりたすが、最初にCDI管理Beanのテストを曞いおみたしょう。

Testing Your Application / Injection into tests

䜜成したテストコヌドは、こちら。

src/test/java/org/littlewings/testing/repository/InMemoryBookRepositoryTest.java

package org.littlewings.testing.repository;

import java.util.List;
import javax.inject.Inject;

import io.quarkus.test.junit.QuarkusTest;
import io.smallrye.mutiny.helpers.test.AssertSubscriber;
import io.smallrye.mutiny.helpers.test.UniAssertSubscriber;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.littlewings.testing.entity.Book;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

@QuarkusTest
public class InMemoryBookRepositoryTest {
    @Inject
    InMemoryBookRepository bookRepository;

    @BeforeEach
    public void setup() {
        List.of(
                Book.create("978-4295008477", "新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]", 2860),
                Book.create("978-4295008583", "マむクロサヌビスパタヌン[実践的システムデザむンのためのコヌド解説]", 5280),
                Book.create("978-1492062653", "Quarkus Cookbook: Kubernetes-optimized Java Solutions", 6376),
                Book.create("978-4295007753", "クラりドネむティブ・アヌキテクチャ 可甚性ず費甚察効果を極める次䞖代蚭蚈の原則", 4290)
        ).forEach(b -> bookRepository.insert(b).subscribe().with(v -> {
        }));
    }

    @AfterEach
    public void teardown() {
        bookRepository.clear().subscribe().with(v -> {
        });
    }

    @Test
    public void findByIsbnTest() {
        UniAssertSubscriber<Book> subscriber =
                bookRepository.findByIsbn("978-4295008477").subscribe().withSubscriber(UniAssertSubscriber.create());

        Book book =
                subscriber
                        .assertCompleted()
                        .getItem();

        assertThat(book.getIsbn(), is("978-4295008477"));
        assertThat(book.getTitle(), is("新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]"));
        assertThat(book.getPrice(), is(2860));
    }

    @Test
    public void findAllTest() {
        UniAssertSubscriber<List<String>> isbnSubscriber =
                bookRepository
                        .findAll()
                        .map(Book::getIsbn)
                        .collect()
                        .asList()
                        .subscribe()
                        .withSubscriber(UniAssertSubscriber.create());

        isbnSubscriber
                .assertCompleted()
                .assertItem(
                        List.of(
                                "978-1492062653",  // price: 6379
                                "978-4295008583",  // price: 5280
                                "978-4295007753",  // price: 4290
                                "978-4295008477"   // price: 2860
                        )
                );

        AssertSubscriber<String> subscriber =
                bookRepository
                        .findAll()
                        .map(Book::getIsbn)
                        .subscribe()
                        .withSubscriber(AssertSubscriber.create(10));

        subscriber
                .assertCompleted()
                .assertItems(
                        "978-1492062653",  // price: 6379
                        "978-4295008583",  // price: 5280
                        "978-4295007753",  // price: 4290
                        "978-4295008477"   // price: 2860
                );
    }

    @Test
    public void putTest() {
        bookRepository
                .insert(Book.create("978-4295009795", "Kubernetes完党ガむド 第2版", 4400))
                .subscribe()
                .withSubscriber(UniAssertSubscriber.create());

        UniAssertSubscriber<Integer> subscriber =
                bookRepository.size().subscribe().withSubscriber(UniAssertSubscriber.create());

        subscriber.assertCompleted().assertItem(5);
    }

    @Test
    public void deleteTest() {
        bookRepository
                .delete("978-4295007753")
                .subscribe()
                .withSubscriber(UniAssertSubscriber.create())
                .assertCompleted();

        UniAssertSubscriber<Integer> subscriber =
                bookRepository.size().subscribe().withSubscriber(UniAssertSubscriber.create());

        subscriber.assertCompleted().assertItem(3);
    }
}

テストクラスには、@QuarkusTestアノテヌションを付䞎したす。

@QuarkusTest
public class InMemoryBookRepositoryTest {

この状態で、CDI管理Beanをふ぀うに@Injectするこずができたす。

    @Inject
    InMemoryBookRepository bookRepository;

InMemoryBookRepositoryクラスで持぀デヌタは、テストの床に初期デヌタ登録、削陀するようにしおいたす。

    @Inject
    InMemoryBookRepository bookRepository;

    @BeforeEach
    public void setup() {
        List.of(
                Book.create("978-4295008477", "新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]", 2860),
                Book.create("978-4295008583", "マむクロサヌビスパタヌン[実践的システムデザむンのためのコヌド解説]", 5280),
                Book.create("978-1492062653", "Quarkus Cookbook: Kubernetes-optimized Java Solutions", 6376),
                Book.create("978-4295007753", "クラりドネむティブ・アヌキテクチャ 可甚性ず費甚察効果を極める次䞖代蚭蚈の原則", 4290)
        ).forEach(b -> bookRepository.insert(b).subscribe().with(v -> {
        }));
    }

    @AfterEach
    public void teardown() {
        bookRepository.clear().subscribe().with(v -> {
        });
    }

この範囲だず、基本的にはJUnit 5を䜿ったテストの話なのですが、SmallRye Mutiniyに関するテストに関しおだけ少し曞いお
おきたしょう。

SmallRye Mutinyにテストに関する情報は、こちらに曞かれおいたす。

How can I write unit / integration tests?

Uniに察するテストの堎合は、UniAssertSubscriberを䜿いたす。

    @Test
    public void findByIsbnTest() {
        UniAssertSubscriber<Book> subscriber =
                bookRepository.findByIsbn("978-4295008477").subscribe().withSubscriber(UniAssertSubscriber.create());

        Book book =
                subscriber
                        .assertCompleted()
                        .getItem();

        assertThat(book.getIsbn(), is("978-4295008477"));
        assertThat(book.getTitle(), is("新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]"));
        assertThat(book.getPrice(), is(2860));
    }

Multiの堎合は、AssertSubscriberを䜿いたす。以䞋は、findAllの結果を1床Uniに倉換しおアサヌションしおいるものず、
Multiのたたアサヌションしおいるものです。

    @Test
    public void findAllTest() {
        UniAssertSubscriber<List<String>> isbnSubscriber =
                bookRepository
                        .findAll()
                        .map(Book::getIsbn)
                        .collect()
                        .asList()
                        .subscribe()
                        .withSubscriber(UniAssertSubscriber.create());

        isbnSubscriber
                .assertCompleted()
                .assertItem(
                        List.of(
                                "978-1492062653",  // price: 6379
                                "978-4295008583",  // price: 5280
                                "978-4295007753",  // price: 4290
                                "978-4295008477"   // price: 2860
                        )
                );

        AssertSubscriber<String> subscriber =
                bookRepository
                        .findAll()
                        .map(Book::getIsbn)
                        .subscribe()
                        .withSubscriber(AssertSubscriber.create(10));

        subscriber
                .assertCompleted()
                .assertItems(
                        "978-1492062653",  // price: 6379
                        "978-4295008583",  // price: 5280
                        "978-4295007753",  // price: 4290
                        "978-4295008477"   // price: 2860
                );
    }

AssertSubscriberを䜿う時は、createの匕数にリク゚ストする数を曞いおおかないず、省略するず0を指定したこずになっお
䞀切Subscribeしおくれたせん。最初、これにハマりたした 。

        AssertSubscriber<String> subscriber =
                bookRepository
                        .findAll()
                        .map(Book::getIsbn)
                        .subscribe()
                        .withSubscriber(AssertSubscriber.create(10));

CDI管理Beanのテストは、こんな感じですね。

ちなみに、@Transactionalアノテヌションをテストで䜿うこずもできるようですが、自分はSmallRye Mutinyを䞭心に扱う予定なので、
この機胜の出番はなさそうです。
※それずも、MicroProfile Context Propagationを䜿えばいいんでしょうか

Testing Your Application / Tests and Transactions

それにしおも、SmallRye Mutinyのサむト、以前からだいぶ雰囲気が倉わりたしたね 。

Mutiny!

テスト内でQuarkusにアクセスするURLを取埗する

続いおは、こちらです。

Testing Your Application / Injecting a URI

Testing Your Application / TestHTTPResource

@TestHTTPResourceずいうアノテヌションを䜿甚するず、QuarkusぞアクセスするためのURLをむンゞェクションできたす。

䜿い方は、こんな感じです。

src/test/java/org/littlewings/testing/rest/InjectUrlTest.java

package org.littlewings.testing.rest;

import java.net.URL;

import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@QuarkusTest
public class InjectUrlTest {
    @TestHTTPResource
    URL rootUrl;

    @TestHTTPResource("book")
    URL pathSpecificUrl;

    @TestHTTPEndpoint(BookResource.class)
    @TestHTTPResource
    URL resourceClassSpecificUrl;

    @Test
    public void injectedUrlTest() {
        Assertions.assertEquals("http://localhost:8083/", rootUrl.toString());
        Assertions.assertEquals("http://localhost:8083/book", pathSpecificUrl.toString());
        Assertions.assertEquals("http://localhost:8083/book", resourceClassSpecificUrl.toString());
    }
}

@QuarkusTestアノテヌションを付䞎したクラスに察しお

@QuarkusTest
public class InjectUrlTest {

@TestHTTPResourceアノテヌションを付䞎したURLを宣蚀するず、QuarkusぞアクセスできるURLhttp://localhost:[port]が
取埗できたす。

    @TestHTTPResource
    URL rootUrl;

パスを指定するこずもできたす。

    @TestHTTPResource("book")
    URL pathSpecificUrl;

@TestHTTPEndpointアノテヌションにJAX-RSリ゜ヌスクラスを指定するず、JAX-RSリ゜ヌスクラスに指定された
@Pathアノテヌションの倀も埋めおくれたす。

    @TestHTTPEndpoint(BookResource.class)
    @TestHTTPResource
    URL resourceClassSpecificUrl;

このため、この機胜は@Pathアノテヌションに䟝存しおおり、JAX-RSリ゜ヌスクラスに@Pathアノテヌションを付䞎しなかった堎合は

//@Path("book")
public class BookResource {

テスト実行時に゚ラヌになりたす。

Caused by: java.lang.RuntimeException: Could not determine the endpoint path for class org.littlewings.testing.rest.BookResource to inject java.net.URL org.littlewings.testing.rest.UrlBookResourceTest.resourceClassSpecificUrl
    at io.quarkus.test.common.http.TestHTTPResourceManager.inject(TestHTTPResourceManager.java:78)

この3パタヌンで、@TestHTTPResourceアノテヌションを䜿っおむンゞェクションしたURLの結果は以䞋になりたす。

    @Test
    public void injectedUrlTest() {
        Assertions.assertEquals("http://localhost:8083/", rootUrl.toString());
        Assertions.assertEquals("http://localhost:8083/book", pathSpecificUrl.toString());
        Assertions.assertEquals("http://localhost:8083/book", resourceClassSpecificUrl.toString());
    }

通垞は、このURLを䜿っおテストコヌドを曞いおいくわけですが、今回はやりたせん。

ずころで、Quakursでのテスト時に䜿われるデフォルトのポヌトは8081なのですが、今回こちらの蚭定を䜿っお倉曎しおいたす。

Testing Your Application / Controlling the test port

今回は以䞋のように定矩しおいるのですが、これをどこで定矩しおいるかはたた埌で曞きたす。

quarkus.http.test-port=8083

ずりあえず、今回のテストの間は、テストにおけるQuarkusのリッスンポヌトは8083ずなりたす。

REST-assuredを䜿っおテストする

先ほどは@TestHTTPResourceアノテヌションを䜿っお、QuarkusにアクセスするためのURLを取埗したしたが、この方法だず
HTTPのテストに関するサポヌトがなにもありたせん。

もっず抜象床の高いテストの方法ずしお、QuarkusではREST-assuredを䜿うこずができたす。

Testing Your Application / RESTassured

@TestHTTPEndpointず組み合わせお䜿うこずで、JAX-RSリ゜ヌスクラスぞアクセスするテストを曞きやすくなりたす。

REST-assured自䜓は独立したREST API向けのテストラむブラリです。

REST Assured

䜿い方は、RestAssuredのJavadoc、Wikiを芋るずだいたいわかりたす。

RestAssured - rest-assured 4.3.3 javadoc

Usage · rest-assured/rest-assured Wiki · GitHub

䜜成したテストコヌドは、こちら。

src/test/java/org/littlewings/testing/rest/BookResourceTest.java

package org.littlewings.testing.rest;

import java.util.List;
import javax.inject.Inject;

import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import org.apache.http.entity.ContentType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.littlewings.testing.entity.Book;
import org.littlewings.testing.repository.InMemoryBookRepository;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasSize;

@QuarkusTest
@TestHTTPEndpoint(BookResource.class)
public class BookResourceTest {
    @Inject
    InMemoryBookRepository bookRepository;

    @BeforeEach
    public void setup() {
        List.of(
                Book.create("978-4295008477", "新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]", 2860),
                Book.create("978-4295008583", "マむクロサヌビスパタヌン[実践的システムデザむンのためのコヌド解説]", 5280),
                Book.create("978-1492062653", "Quarkus Cookbook: Kubernetes-optimized Java Solutions", 6376),
                Book.create("978-4295007753", "クラりドネむティブ・アヌキテクチャ 可甚性ず費甚察効果を極める次䞖代蚭蚈の原則", 4290)
        ).forEach(b -> bookRepository.insert(b).subscribe().with(v -> {
        }));
    }

    @AfterEach
    public void teardown() {
        bookRepository.clear().subscribe().with(v -> {
        });
    }

    @Test
    public void findByIsbnTest() {
        given()
                .pathParam("isbn", "978-4295008477")
                .when()
                .get("{isbn}")
                .then()
                .assertThat()
                .statusCode(200)
                .body("title", is("新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]"))
                .body("price", is(2860));
    }

    @Test
    public void findAllTest() {
        given()
                .when()
                .get()
                .then()
                .assertThat()
                .statusCode(200)
                .body("price", is(List.of(6376, 5280, 4290, 2860)));
    }

    @Test
    public void putTest() {
        given()
                .pathParam("isbn", "978-4295009795")
                .contentType(ContentType.APPLICATION_JSON.getMimeType())
                .body(Book.create("978-4295009795", "Kubernetes完党ガむド 第2版", 4400))
                .when()
                .put("{isbn}")
                .then()
                .assertThat()
                .statusCode(200);

        given()
                .when()
                .get()
                .then()
                .assertThat()
                .statusCode(200)
                .body("price",  hasSize(5));  // 4 + 1
    }

    @Test
    public void deleteTest() {
        given()
                .pathParam("isbn", "978-4295008583")
                .when()
                .delete("{isbn}")
                .then()
                .assertThat()
                .statusCode(204);

        given()
                .when()
                .get()
                .then()
                .assertThat()
                .statusCode(200)
                .body("price",  hasSize(3));  // 4 - 1
    }
}

テストクラスに、@QuarkusTestアノテヌションず、テスト察象のJAX-RSリ゜ヌスクラスを指定しお@TestHTTPEndpoint
アノテヌションを付䞎したす。

@QuarkusTest
@TestHTTPEndpoint(BookResource.class)
public class BookResourceTest {

テストデヌタは、CDI管理Beanのテストの時ず同様、テストごずに登録、削陀するようにしおいたす。

    @Inject
    InMemoryBookRepository bookRepository;

    @BeforeEach
    public void setup() {
        List.of(
                Book.create("978-4295008477", "新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]", 2860),
                Book.create("978-4295008583", "マむクロサヌビスパタヌン[実践的システムデザむンのためのコヌド解説]", 5280),
                Book.create("978-1492062653", "Quarkus Cookbook: Kubernetes-optimized Java Solutions", 6376),
                Book.create("978-4295007753", "クラりドネむティブ・アヌキテクチャ 可甚性ず費甚察効果を極める次䞖代蚭蚈の原則", 4290)
        ).forEach(b -> bookRepository.insert(b).subscribe().with(v -> {
        }));
    }

    @AfterEach
    public void teardown() {
        bookRepository.clear().subscribe().with(v -> {
        });
    }

あずは、こんな感じでJAX-RSリ゜ヌスクラスぞHTTPリク゚ストを実行し、アサヌションするこずができたす。

    @Test
    public void findByIsbnTest() {
        given()
                .pathParam("isbn", "978-4295008477")
                .when()
                .get("{isbn}")
                .then()
                .assertThat()
                .statusCode(200)
                .body("title", is("新䞖代Javaプログラミングガむド[Java SE 10/11/12/13ず蚀語拡匵プロゞェクト]"))
                .body("price", is(2860));
    }

REST-assuredは初めお䜿ったのですが、bodyでJSONのパスを指定しおアサヌションしたりできお䟿利ですね。

パスにマッチする芁玠が耇数あった堎合は、コレクションずしおアサヌションできたす。

    @Test
    public void findAllTest() {
        given()
                .when()
                .get()
                .then()
                .assertThat()
                .statusCode(200)
                .body("price", is(List.of(6376, 5280, 4290, 2860)));
    }

テスト時に蚭定を倉える

最埌は、テスト時に蚭定ファむルで指定したプロパティの倀を倉曎しおみたしょう。

もずもず、Quarkusのデフォルトの蚭定ファむルに以䞋の定矩を曞いおいたした。

src/main/resources/application.properties

app.config.message1=Hello World!!
app.config.message2=Hello Quarkus!!
app.config.message3=Wow!!

テスト時はこの倀の䞀郚を倉曎したい、ずいうシチュ゚ヌションを考えおみたす。

ドキュメントを芋おいるず、どうやらProfileずいうものがあるようです。

Testing Your Application / Testing Different Profiles

テストを実行しおみるず

$ mvn test

どうやらtestずいうProfileになっおいるようです。

2021-03-07 00:42:24,190 INFO  [io.quarkus] (main) Quarkus 1.12.1.Final on JVM started in 2.173s. Listening on: http://localhost:8083
2021-03-07 00:42:24,196 INFO  [io.quarkus] (main) Profile test activated. 
2021-03-07 00:42:24,197 INFO  [io.quarkus] (main) Installed features: [cdi, mutiny, resteasy, resteasy-jackson, resteasy-mutiny, smallrye-context-propagation

ここで、以䞋のドキュメントを芋おみたす。

Configuring Your Application / Configuration Profiles

デフォルトでは、3぀のProfileがあるようです。

  • dev - Activated when in development mode (i.e. quarkus:dev)
  • test - Activated when running tests
  • prod - The default profile when not running in development or test mode

そしお、%Profile名.[プロパティ]ずいう蚘茉で察象のProfileで動䜜しおいる時に有効なプロパティを蚭定できるようです。

たずえば、こんな感じですね。
※実際には、このようには倉曎しおいたせん䟋です

src/main/resources/application.properties

app.config.message1=Hello World!!
app.config.message2=Hello Quarkus!!
app.config.message3=Wow!!


%test.app.config.message2=Test Hello Quarkus!!

これでもいいのですが、テスト甚の蚭定をsrc/main/resourcesの方に曞くのはちょっずな、ず。

なので、テスト甚の蚭定ファむルを䜜成したいず思いたす。Configuration for MicroProfileのAPIで、カスタムの蚭定ファむルを
远加するこずができたす。

Configuration Reference / Custom configuration sources

GitHub - eclipse/microprofile-config: MicroProfile Configuration Feature

こんな蚭定ファむルにしたした。

src/test/resources/test-application.properties

config_ordinal = 300

quarkus.http.test-port=8083

%test.app.config.message2=Test Hello Quarkus!!
app.config.message3=Oops!!

この蚭定フィアルを読むようなConfigSourceProviderむンタヌフェヌスの実装クラスを䜜成しお

src/test/java/org/littlewings/testing/config/TestApplicationPropertiesConfigSourceProvider.java

package org.littlewings.testing.config;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import io.smallrye.config.PropertiesConfigSource;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.ConfigSourceProvider;

public class TestApplicationPropertiesConfigSourceProvider implements ConfigSourceProvider {
    @Override
    public Iterable<ConfigSource> getConfigSources(ClassLoader forClassLoader) {
        return List
                .of("test-application.properties")
                .stream()
                .map(forClassLoader::getResource)
                .filter(Objects::nonNull)
                .map(path -> {
                    try {
                        return new PropertiesConfigSource(path);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                })
                .collect(Collectors.toList());
    }
}

以䞋のファむルを䜜り、䜜成したConfigSourceProviderむンタヌフェヌスの実装クラス名を曞いおおきたす。

src/test/resources/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSourceProvider

org.littlewings.testing.config.TestApplicationPropertiesConfigSourceProvider

たた、远加した蚭定ファむルに曞いおいるconfig_ordinalずいう倀は、優先床です。

src/test/resources/test-application.properties

config_ordinal = 300

quarkus.http.test-port=8083

%test.app.config.message2=Test Hello Quarkus!!
app.config.message3=Oops!!

今回、%test.app.config.message2ずいうProfile別の指定ず、application.propertiesでの定矩ずたったく同じキヌである
app.config.message3を䜿い、䞡方ずもapplication.propertiesより優先されるこずを確認したす。

application.properties自䜓がどのような優先床になっおいるかですが、これは゜ヌスコヌドを芋るずわかりたす。

JARファむルの䞭の堎合、250。

https://github.com/quarkusio/quarkus/blob/1.12.1.Final/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java#L57

META-INF/microprofile-config.propertiesファむルずしお登録した堎合、240。

https://github.com/quarkusio/quarkus/blob/1.12.1.Final/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java#L80

ファむルシステム䞊の堎合、260。

https://github.com/quarkusio/quarkus/blob/1.12.1.Final/core/runtime/src/main/java/io/quarkus/runtime/configuration/ApplicationPropertiesConfigSource.java#L100

なので、新しく䜜成したtest-application.propertiesファむルの優先床はconfig_ordinal = 300ずし、application.propretiesよりも
高く蚭定しおいたす。

あずは、テストを曞くだけです。こちらも、REST-assuredを䜿っおテストを曞きたす。

src/test/java/org/littlewings/testing/rest/ConfigResourceTest.java

package org.littlewings.testing.rest;

import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
@TestHTTPEndpoint(ConfigResource.class)
public class ConfigResourceTest {
    @Test
    public void message1Test() {
        given()
                .when()
                .get("message1")
                .then()
                .assertThat()
                .statusCode(200)
                .body(is("Hello World!!"));
    }

    @Test
    public void message2Test() {
        given()
                .when()
                .get("message2")
                .then()
                .assertThat()
                .statusCode(200)
                .body(is("Test Hello Quarkus!!"));
    }

    @Test
    public void message3Test() {
        given()
                .when()
                .get("message3")
                .then()
                .assertThat()
                .statusCode(200)
                .body(is("Oops!!"));
    }
}

このテストに曞いた通り、test-application.propertiesで定矩したプロパティに぀いおは、そちらの方が優先されおいるこずが
確認できたす。

今回確認した内容は、こんな感じです。

テストに関する話題で、扱わなかったこず

テストのガむドに茉っおいお、今回扱わなかったのはこのあたりです。

Testing Your Application / Applying Interceptors to Tests

Testing Your Application / Tests and Transactions

Testing Your Application / Enrichment via QuarkusTest*Callback

Testing Your Application / Testing Different Profiles

Testing Your Application / Mock Support

Testing Your Application / Starting services before the Quarkus application starts

Testing Your Application / Native Executable Testing

Testing Your Application / Running @QuarkusTest from an IDE

䞀郚、少し觊れたものもありたすが、だいたいこんな感じです。

モック、トランザクション、Profile、テストの前に別のサヌビスを動かす、あたりはそのうち䜿うこずになるかもなぁず思ったり。

今回は、こんなずころでおしたい。