将来を見据えたウェブ・アプリケーションの構築:The Codestのエキスパート・チームによる洞察
The Codestが、最先端技術を駆使してスケーラブルでインタラクティブなウェブアプリケーションを作成し、あらゆるプラットフォームでシームレスなユーザー体験を提供することにどのように秀でているかをご覧ください。The Codestの専門知識がどのようにデジタルトランスフォーメーションとビジネス...
より簡単にテストを行う方法をお探しですか?お任せください!以下の記事をチェックして、それを可能にする方法を学んでください。
現代のアプリケーション開発は、あるシンプルなルールに基づいている:
コンポジションを使用する
私たちは、クラス、関数、サービスを組み合わせて、より大きなソフトウェアの一部とする。この最後の要素がマイクロサービスの基礎であり 六角形建築.私たちは、既存のソリューションを使用し、私たちのソフトウェアとそれらを統合し、直接、次の段階に進みたいと考えています。 マーケット.
アカウント登録を処理し、ユーザーデータを保存したいですか?OAuthサービスの1つを選ぶことができます。あなたのアプリケーションは、何らかの購読や支払いを提供していますか?これを処理するのに役立つサービスがたくさんあります。あなたのウェブサイトに分析が必要ですが、GDPRを理解していませんか?お気軽に、すぐに使えるソリューションをご利用ください。
ビジネスの観点からはとても簡単に開発できるものが、簡単なテストを書く瞬間には頭痛の種になるかもしれない。
ユニットテストはとてもシンプルだ。ルールさえ守れば、テスト環境と コード は健康である。それはどんなルールですか?
統合テストを書こうとすると、すべてが複雑になる。いくつかのサービスをまとめてテストするのは悪くない。しかし、データベースやメッセージング・サービスのような外部リソースを使用するサービスをテストする必要がある場合、それはトラブルの元となる。
何年も前のことだが、データベースなどを使って統合テストを行おうとしたとき、2つの選択肢があった:
どちらも長所があり、短所もある。しかし、どちらもさらなる複雑さをもたらす。例えば、ローカルホスト上でのオラクルDBのインストールや管理などである。時には、テストに同意する必要があるなど、プロセス上の不都合もあった。 チーム JMSの使用について...テストを実行するたびに。
この10年間で、コンテナ化という考え方が業界で認知されるようになった。だから、統合テストの問題の解決策としてコンテナを選ぶのは自然な判断だ。これはシンプルでクリーンなソリューションだ。プロセスのビルドを実行するだけで、すべてがうまくいく!信じられませんか?mavenビルドのシンプルな構成を見てみよう:
<ビルド
<プラグイン
<プラグイン
com.dkanejs.maven.pluginsの場合
docker-compose-maven-pluginがあります。
4.0.0</バージョン
<エクセキューション
<エクセキューション
アップ</id
テストコンパイル</フェーズ
<ゴール
アップ</ゴール
</ゴール
<構成
${プロジェクト.basedir}/docker-compose.ymlを参照してください。
true。
</execution
<実行
ダウン</id
post-integration-test</フェーズ
<ゴール
ダウン</ゴール
</ゴール
<コンフィギュレーション
${project.basedir}/docker-compose.yml。
true。
</execution
</ビルド
そして docker-compose.yml
ファイルもなかなか良さそうだ!
バージョン"3.5"
サービス
postgres:
コンテナ名: reactivedb
image: postgres:13.2
再起動: 常に
環境
- POSTGRES_USER=admin
- POSTGRES_PASSWORD=パスワード
- POSTGRES_DB=cities
ポート
- "5432:5432"
ボリューム
- POSTGRES_DATA:/データ/DB
pgadmin:
コンテナ名: pgadmin4
イメージ: dpage/pgadmin4
再起動: 常に
環境変数
pgadmin_default_email: [email protected]
PGADMIN_DEFAULT_PASSWORD: パスワード
ポート
- "15050:80"
ボリューム:
- pgadmin_data:/data/pgadmin
ボリューム:
ボリューム: pgadmin_data:/data/pgadmin
pgadmin_data:
しかし、ここに問題があることにお気づきだろうか?
上の例はとてもシンプルです。1つのpostgresデータベースとpgAdminだけです。次のように実行します。
バッシュ
$ mvn clean verify
そして、mavenプラグインがコンテナを起動し、テストが終わったらコンテナをオフにする。プロジェクトが大きくなり、composeファイルも大きくなると問題が発生する。その都度、すべてのコンテナを起動する必要があり、ビルド全体を通してコンテナが生き続けることになる。プラグインの実行設定を変更することで、少しは状況を改善できますが、それだけでは不十分です。最悪のシナリオでは、テストが始まる前にコンテナがシステムリソースを使い果たしてしまう!
問題はこれだけではない。IDEから統合テストをひとつも実行できないのだ。その前に、手作業でコンテナを起動する必要がある。さらに、次のmavenの実行で、それらのコンテナは破棄される(次のセクションを参照)。 ダウン
実行)。
つまり、このソリューションは大きな貨物船のようなものだ。すべてがうまく機能すればそれでいい。予期せぬ、あるいは一般的でない行動は、何らかの災難につながる。
しかし、テストからコンテナを実行できるとしたらどうだろう?このアイデアは良さそうだし、すでに実装されている。 テストコンテナこのプロジェクトについて話しているのだから、ここに我々の問題に対する解決策がある。理想的ではないが、完璧な人間などいない。
これは ジャワ ライブラリはJUnitとSpockテストをサポートし、軽量で簡単なDockerコンテナの実行方法を提供する。これを見て、コードを書いてみよう!
始める前に、設定をチェックする必要がある。 テスト容器 が必要だ:
特定のOSとCIの要件の詳細については、以下を参照してください。
で ドキュメンテーション.
さて、次は次の行を追加する番だ。 pom.xml
.
<プロジェクト
<依存関係管理
<依存関係
<依存関係
org.testcontainersの場合
testcontainers-bom。
${testcontaines.version}となります。
pom
インポート</スコープ
</dependencies
</dependencies
<依存関係
<依存関係
org.postgresql。
postgresql。
ランタイム。
<依存関係
org.testcontainersの場合
postgresql。
テスト。
<依存関係
org.testcontainersの場合
junit-jupiterです。
テスト。
</プロジェクト
私はこうしている。 テスト容器 バージョン 1.17.3
ただし、最新のものをご自由にお使いください。
最初のステップは、コンテナのインスタンスを用意することだ。これはテストの中で直接行うこともできるが、独立したクラスの方が見栄えがよい。
public class Postgres13TC extends PostgreSQLContainer {.
private static final Postgres13TC TC = new Postgres13TC();
プライベートPostgres13TC()
super("postgres:13.2");
}
public static Postgres13TC getInstance() { { { { { Postgres13TCを取得します。
TC を返します;
}
オーバーライド
public void start() {
super.start();
System.setProperty("DB_URL", TC.getJdbcUrl());
System.setProperty("DB_USERNAME", TC.getUsername());;
System.setProperty("DB_PASSWORD", TC.getPassword());
}
オーバーライド
public void stop() { // 何もしない。
// 何もしない。これは共有インスタンスだ。この操作はJVMに任せましょう。
}
}
テストの最初に ポストグレス13TC
.このクラスはコンテナに関する情報を扱うことができる。ここで最も重要なのは、データベース接続文字列と認証情報である。それでは、とても簡単なテストを書いてみましょう。
テストコンテナ
クラス SimpleDbTest
コンテナ
private static Postgres13TC = Postgres13TC.getInstance();
テスト
void testConnection() {
assumeThat(postgres13TC.isRunning());
var connectionProps = new Properties();
connectionProps.put("user", postgres13TC.getUsername());
connectionProps.put("password", postgres13TC.getPassword());
try (Connection = DriverManager.getConnection(postgres13TC.getJdbcUrl()、
connectionProps))
var resultSet = connection.prepareStatement("Select 1").executeQuery();
resultSet.next();
assertThat(resultSet.getInt(1)).isEqualTo(1);
} catch (SQLException sqlException) { {.
assertThat((Exception) sqlException).doesNotThrowAnyException();
}
}
}
ここではJUnit 5を使っている。アノテーション テストコンテナ
は、テスト環境のコンテナを制御するエクステンションの一部である。を持つすべてのフィールドを見つけます。 コンテナ
アノテーションと、それぞれスタートとストップのコンテナ。
前にも述べたように、プロジェクトではSpring Bootを使っている。この場合、もう少しコードを書く必要がある。最初のステップは、追加の設定クラスを作成することです。
Slf4j
public class ContainerInit implements
ApplicationContextInitializerを実装しています。
public static Postgres13TC;
スタティック
postgres13TC = Postgres13TC.getInstance();
postgres13TC.start();
}
オーバーライド
public void initialize(ConfigurableApplicationContext applicationContext) { } @override
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext、
"spring.datasource.url=" + postgres13TC.getJdbcUrl()、
"spring.datasource.username=" + postgres13TC.getUsername()、
"spring.datasource.password=" + postgres13TC.getPassword()、
"db.host=" + postgres13TC.getHost()、
"db.port=" + postgres13TC.getMappedPort(postgres13TC.POSTGRESQL_PORT)、
"db.name=" + postgres13TC.getDatabaseName()、
"db.username=" + postgres13TC.getUsername()、
"db.password=" + postgres13TC.getPassword()
);
}
}
このクラスは、既存のプロパティを テスト容器.最初の3つのプロパティは、標準的な Spring のプロパティです。次の5つは追加のカスタムプロパティで、liquibase のような他のリソースや拡張機能を設定するために使用できます:
spring.liquibase.change-log=classpath:/db/changelog/dbchangelog.xml
spring.liquibase.url=jdbc:postgresql://${db.host:localhost}:${db.port:5432}/${db.name:cities}。
spring.liquibase.user=${db.username:admin}。
spring.liquibase.password=${db.password:password} です。
spring.liquibase.enabled=true
さて、次は簡単な統合テストを定義する番だ。
SpringBootTest(webEnvironment = RANDOM_PORT)
@AutoConfigureTestDatabase(replace = NONE)
@ContextConfiguration(initializers = ContainerInit.class)
テストコンテナ
クラス DummyRepositoryTest
自動化
private DummyRepository;
テスト
void shouldReturnDummy() { 以下のようにします。
var byId = dummyRepository.getById(10L);
var expected = new Dummy();
expected.setId(10L);
assertThat(byId).completes().emitsCount(1).emits(expected);
}
}
ここで少し注釈を加えておく。
SpringBootTest(webEnvironment = RANDOM_PORT)
- はテストをSpring Bootテストとしてマークし、springコンテキストを開始します。AutoConfigureTestDatabase(replace = NONE)
- これらのアノテーションは、spring test 拡張モジュールが postgres データベースの設定をメモリ設定の H2 に置き換えてはいけないことを示しています。ContextConfiguration(イニシャライザ = ContainerInit.class)
- 追加の春コンテキストテストコンテナ
- 前述のように、このアノテーションはコンテナのライフサイクルを制御する。この例ではリアクティブ・リポジトリーを使用していますが、一般的なJDBCやJPAのリポジトリーでも同じように動作します。
これでこのテストを実行できる。最初の実行の場合、エンジンはdocker.hubからイメージをプルする必要がある。これには少し時間がかかる。その後、2つのコンテナが実行されたことがわかるだろう。1つはpostgresで、もう1つはTestcontainersコントローラだ。この2つ目のコンテナは実行中のコンテナを管理し、JVMが予期せず停止した場合でも、コンテナの電源を切って環境をクリーンアップする。
テスト容器 は非常に使いやすいツールで、Dockerコンテナを使用した統合テストを作成するのに役立ちます。これにより、柔軟性が増し、開発スピードが向上します。テスト構成を適切にセットアップすることで、新人開発者の受け入れに必要な時間が短縮される。彼らはすべての依存関係をセットアップする必要はなく、ただ選択した設定ファイルを用いて書かれたテストを実行するだけです。