TestContainers を使ってR2DBCのテストを作成する
TestContainers はR2DBCもサポートしていますが、SQLServerとの組み合わせはなかなか情報なく、とりあえず動くところまできたので、まとめておきます。
R2DBC support
環境
-
Windows11
-
Docker Desktop
-
Java17
-
SpringBoot 2.7
-
SQLServer 2019
-
Maven
-
TestContainers
準備するもの
pom.xml
まずはpom.xmlから抜粋。省略してますが、lombok使ってます。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath />
</parent>
<properties>
<testcontainer.version>1.17.6</testcontainer.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-mssql</artifactId>
<version>1.0.0.RELEASE</version>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>r2dbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mssqlserver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>11.2.3.jre17</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainer.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
bom使ってますが、使わない場合は org.testcontainers:testcontainers をdependencyに追加すれば良さそうです。
サイトやDBによってdependencyに追加するライブラリの組み合わせが違うので、なかなかエラーが解消できませんでしたが、SQLServerの場合だと、この組み合わせでできました。多いな。。
application-test.yml
DBへの接続、初期化、おまけでログの設定を記述します。
TC_IMAGE_TAG に microsoft-mssql-server にあるdocker tag を記載します。
spring.sql.init.mode : always はこれを記述しないとschema.sqlが読み込まれなかったので、書いてます。デフォルトで呼ばれるはずなんだけどな?
spring:
r2dbc:
url: r2dbc:tc:sqlserver:///?TC_IMAGE_TAG=2019-latest
sql:
init:
mode: always # schema.sql を読ませるために設定
logging:
level:
io.r2dbc.mssql.QUERY: DEBUG # for queries
io.r2dbc.mssql.PARAM: DEBUG # for parameters
org.springframework.r2dbc: DEBUG
container-license-acceptance.txt
SQLServerなどライセンスが必要なコンテナを使う場合は、これが必要なようです。
src/test/resources/ の下に配置します。
Due to licencing restrictions you are required to accept an EULA for this container image. To indicate that you accept the MS SQL Server image EULA, call the acceptLicense() method, or place a file at the root of the classpath named container-license-acceptance.txt, e.g. at src/test/resources/container-license-acceptance.txt. This file should contain the line: mcr.microsoft.com/mssql/server:2017-CU12 (or, if you are overriding the docker image name/tag, update accordingly).
Please see the microsoft-mssql-server image documentation for a link to the EULA document.
mcr.microsoft.com/mssql/server:2019-latest // 使用するコンテナイメージのタグを指定する
※複数のコンテナを使う場合はこのファイルにコンテナイメージを追記していくみたいです。
schema.sql
src/test/resources の配下においておくと、Springが起動時に読んでくれます。確か。
今回は簡単なCompanyテーブルを作っておきます。
CREATE TABLE [dbo].[Company](
[Id] [int] IDENTITY(1, 1) NOT NULL,
[CompanyName] [nvarchar](511) NOT NULL,
CONSTRAINT [PK_Company] PRIMARY KEY CLUSTERED ([Id] ASC) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON,
OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF
) ON [PRIMARY]
) ON [PRIMARY];
Entity/Repository
Company とマッピングさせるEntityとRepositoryです。
@AllArgsConstructor
@NoArgsConstructor
@Data
@Table("Company")
public class Company implements Serializable {
private static final long serialVersionUID = 1L;
@GeneratedValue
@Id
@Column("Id")
private Integer id;
@Column("CompanyName")
private String companyName;
}
public interface CompanyRepository extends ReactiveCrudRepository<Company, Integer> {
}
テストコード
さて、ようやく準備が整ったのでテストコードです。
ちなみに、data.sqlもresourcesのルートに配置しておくと、データをinsertしてくれますが、SQLエラーが解消できなかったので、今回は諦めて、テストコードでデータを投入してます。
解決できたら追記するかも。
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest;
import org.springframework.test.context.ActiveProfiles;
import org.testcontainers.junit.jupiter.Testcontainers;
@Testcontainers
@DataR2dbcTest
@ActiveProfiles("test")
class CompanyRepositoryTest {
@Autowired
private CompanyRepository companyRepository;
@Test
void testFindById() {
// data.sql でエラーにどうしてもなるので、仕方なくsaveする
var c = new Company();
c.setCompanyName("株式会社丸さんかく");
companyRepository.save(c).subscribe();
var actual = companyRepository.findOneById(1).block();
assertEquals(c.getCompanyName(), actual.getCompanyName());
}
}
テスト自体はあんまり意味ないですが、データ取得の確認はこんな感じ。
@DataR2dbcTest で読み込むレイヤーを絞ってるので、少しは速く起動できるんじゃないかなと思ったり。
それでは、良きテストライフを。
Discussion