JavaRush /Java Blog /Random-JA /データベースに関連するものをすべて追加します。(パート 2) - 「Java プロジェクトの A から Z まで」...
Roman Beekeeper
レベル 35

データベースに関連するものをすべて追加します。(パート 2) - 「Java プロジェクトの A から Z まで」

Random-JA グループに公開済み
こんにちは、みんな。思い出させてください:最初の部分ではFlyway を追加しました。続けましょう。

docker-compose.yml へのデータベースの追加

次の段階では、メインの docker-compose.yml でデータベースの操作を設定します。データベースを docker-compose ファイルに追加しましょう。
version: '3.1'

services:
 jrtb-bot:
   depends_on:
     - jrtb-db
   build:
     context: .
   environment:
     BOT_NAME: ${BOT_NAME}
     BOT_TOKEN: ${BOT_TOKEN}
     BOT_DB_USERNAME: ${BOT_DB_USERNAME}
     BOT_DB_PASSWORD: ${BOT_DB_PASSWORD}
   restart: always
 jrtb-db:
   image: mysql:5.7
   restart: always
   environment:
     MYSQL_USER: ${BOT_DB_USERNAME}
     MYSQL_PASSWORD: ${BOT_DB_PASSWORD}
     MYSQL_DATABASE: 'jrtb_db'
     MYSQL_ROOT_PASSWORD: 'root'
   ports:
     - '3306:3306'
   expose:
     - '3306'
次の行もアプリケーションに追加しました。
depends_on:
 - jrtb-db
これは、データベースが起動するのを待ってからアプリケーションを起動することを意味します。次に、データベースを操作するために必要なさらに 2 つの変数が追加されていることがわかります。
${BOT_DB_USERNAME}
${BOT_DB_PASSWORD}
Telegram ボットの場合と同じ方法で、環境変数を介して docker-compose でそれらを取得します。これを行ったのは、データベースのユーザー名とそのパスワードの値を設定する場所が 1 か所だけになるようにするためです。これらをアプリケーションの Docker イメージとデータベースの Docker コンテナに渡します。次に、Dockerfile を更新して、SpringBoot にデータベースの変数を受け入れるように教える必要があります。
FROM adoptopenjdk/openjdk11:ubi
ARG JAR_FILE=target/*.jar
ENV BOT_NAME=test.javarush_community_bot
ENV BOT_TOKEN=1375780501:AAE4A6Rz0BSnIGzeu896OjQnjzsMEG6_uso
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}", "-Dbot.token=${BOT_TOKEN}", "-Dspring.datasource.username=${BOT_DB_USERNAME}", "-jar", "app.jar"]
次に、データベース変数を Dockerfile に追加します。
ENV BOT_DB_USERNAME=jrtb_db_user
ENV BOT_DB_PASSWORD=jrtb_db_password
変数の値は異なります。ただし、Dockerfile に渡す値にはデフォルト値が必要なので、デフォルト値を入力しました。最後の行を 2 つの要素で展開します。これを使用して、DB ユーザー名とパスワードをアプリケーション起動に渡します。
"-Dspring.datasource.password=${BOT_DB_PASSWORD}", "-Dbot.username=${BOT_NAME}"
Dockerfile の最後の行 (ENTRYPOINT で始まる行) は折り返さないでください。転送を行う場合、このコードは機能しません。 最後のステップは、start.shファイルを更新して変数をデータベースに渡すことです。
#!/bin/bash

# Pull new changes
git pull

# Prepare Jar
mvn clean
mvn package

# Ensure, that docker-compose stopped
docker-compose stop

# Add environment variables
export BOT_NAME=$1
export BOT_TOKEN=$2
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'

# Start new deployment
docker-compose up --build -d
docker-compose を実行する前に環境変数を追加する方法はすでに知っています。これを行うには、export var_name=var_value を実行するだけです。したがって、追加するのは 2 行だけです。
export BOT_DB_USERNAME='prod_jrtb_db_user'
export BOT_DB_PASSWORD='Pap9L9VVUkNYj99GCUCC3mJkb'
ここでデータベースのユーザー名とパスワードを設定します。もちろん、ボットの名前とトークンの場合と同様に、bash スクリプトの実行時にこれらの変数を渡すことも可能です。しかし、これは不要であるように私には思えます。実際にデータベースにアクセスするには、データベースがデプロイされるサーバーの IP を知っており、要求に対して許可される IP アドレスのリストに含まれている必要があります。私としては、もうこれで十分です。基礎が築かれました。開発者にとってよりわかりやすいこと、つまりコードを書くことができるようになりました。それまでは、私たちは DevOps エンジニアが行うこと、つまり環境のセットアップを行っていました。

リポジトリ層の追加

通常、アプリケーションには次の 3 つの層があります。
  1. コントローラーはアプリケーションへのエントリー ポイントです。
  2. サービスはビジネス ロジックが機能する場所です。これについてはすでに部分的に理解しています。SendMessageService はビジネス ロジックを明示的に表しています。
  3. リポジトリはデータベースを操作する場所です。私たちの場合、これは電報ボットです。
次に、3 番目の層であるリポジトリを追加します。ここでは、Spring エコシステムのプロジェクトである Spring Data を使用します。それが何であるかについては、ハブレに関するこの記事をご覧ください。いくつかの点を知って理解する必要があります。
  1. JDBC を使用する必要はありません。より高い抽象化を直接使用します。つまり、テーブルに対応する POJO をデータベースに保存します。このようなクラスは、 Java Persistence APIで正式に呼び出されているため、entity と呼びます(これは、ORM を通じてデータベースを操作するための共通のインターフェースのセットです。つまり、JDBC での操作を抽象化したものです)。データベースに保存するエンティティ クラスがあり、それらは必要なテーブルに正確に書き込まれます。データベース内を検索すると、同じオブジェクトが返されます。
  2. Spring Data は、 JpaRepositoryCrudRepositoryなどの一連のインターフェースの使用を提案しています。他のインターフェースもあります。完全なリストは、ここで見つけることができます。利点は、メソッドを実装しなくても使用できることです (!)。さらに、インターフェイスに新しいメソッドを記述できる特定のテンプレートがあり、それらは自動的に実装されます。
  3. Spring は開発を可能な限り簡素化します。これを行うには、独自のインターフェイスを作成し、上記で説明したインターフェイスを継承する必要があります。Spring がこのインターフェースを使用する必要があることを認識できるように、Repository アノテーションを追加します。
  4. 存在しないデータベースを操作するためのメソッドを作成する必要がある場合でも、これは問題ではありません。それを作成します。そこで何をどのように行うかを説明します。
この記事では、TelegramUser のパス全体に沿って追加を行い、この部分を例として示します。残りを他のタスクに拡張していきます。つまり、/start コマンドを実行すると、ユーザーのデータベースに active = true が書き込まれます。これは、ユーザーがボットを使用していることを意味します。ユーザーがすでにデータベースに存在する場合は、フィールド active = true を更新します。/stop コマンドを実行するとき、ユーザーは削除されませんが、アクティブなフィールドが false に更新されるだけです。これにより、ユーザーがボットを再度使用したい場合にボットを開始して、中断したところから再開できるようになります。そして、テスト時に何かが起こっていることを確認できるように、アクティブ ユーザーの数を表示する /stat コマンドを作成します。ボット、コマンド、サービス パッケージの隣にリポジトリパッケージを作成します。このパッケージでは、別の 1 つのエンティティを作成します。エンティティ パッケージで TelegramUser クラスを作成します。
package com.github.javarushcommunity.jrtb.repository.entity;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

/**
* Telegram User entity.
*/
@Data
@Entity
@Table(name = "tg_user")
public class TelegramUser {

   @Id
   @Column(name = "chat_id")
   private String chatId;

   @Column(name = "active")
   private boolean active;
}
ここでは、javax.persistence パッケージからのすべてのアノテーションがあることがわかります。これらは、すべての ORM 実装に使用される共通のアノテーションです。デフォルトでは、Spring Data Jpa は Hibernate を使用しますが、他の実装も使用できます。私たちが使用するアノテーションのリストは次のとおりです。
  • エンティティ- これがデータベースを操作するためのエンティティであることを示します。
  • テーブル- ここでテーブルの名前を定義します。
  • Id - 注釈は、テーブル内のどのフィールドが主キーになるかを示します。
  • - テーブルからフィールドの名前を決定します。
次に、データベースを操作するためのインターフェイスを作成します。通常、このようなインターフェイスの名前は、テンプレート EntiryNameRepository を使用して記述されます。TelegramuserRepository を作成します。
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
* {@link Repository} for handling with {@link TelegramUser} entity.
*/
@Repository
public interface TelegramUserRepository extends JpaRepository<TelegramUser, String> {
   List<TelegramUser> findAllByActiveTrue();
}
ここでは、どこにも実装していないfindAllByActiveTrue()メソッド を追加した方法を示します。しかし、だからといって彼の仕事が止まるわけではない。Spring Data は、アクティブ フィールドが true である tg_user テーブルからすべてのレコードを取得する必要があることを理解します。TelegramUser エンティティを操作するためのサービスを追加します (他のエンティティのサービスが別のエンティティのリポジトリと直接通信できないという状況で、SOLID からの依存関係反転を使用します (そのエンティティのサービスを介してのみ))。パッケージ内にサービス TelegramUserService を作成します。これには、今のところ、ユーザーの保存、ID によるユーザーの取得、アクティブ ユーザーのリストの表示などのいくつかのメソッドがあります。まず、TelegramUserService インターフェイスを作成します。
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
* {@link Service} for handling {@link TelegramUser} entity.
*/
public interface TelegramUserService {

   /**
    * Save provided {@link TelegramUser} entity.
    *
    * @param  telegramUser provided telegram user.
    */
   void save(TelegramUser telegramUser);

   /**
    * Retrieve all active {@link TelegramUser}.
    *
    * @return the collection of the active {@link TelegramUser} objects.
    */
   List<TelegramUser> retrieveAllActiveUsers();

   /**
    * Find {@link TelegramUser} by chatId.
    *
    * @param chatId provided Chat ID
    * @return {@link TelegramUser} with provided chat ID or null otherwise.
    */
   Optional<TelegramUser> findByChatId(String chatId);
}
そして実際、TelegramUserServiceImpl の実装は次のようになります。
package com.github.javarushcommunity.jrtb.service;

import com.github.javarushcommunity.jrtb.repository.TelegramUserRepository;
import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

/**
* Implementation of {@link TelegramUserService}.
*/
@Service
public class TelegramUserServiceImpl implements TelegramUserService {

   private final TelegramUserRepository telegramUserRepository;

   @Autowired
   public TelegramUserServiceImpl(TelegramUserRepository telegramUserRepository) {
       this.telegramUserRepository = telegramUserRepository;
   }

   @Override
   public void save(TelegramUser telegramUser) {
       telegramUserRepository.save(telegramUser);
   }

   @Override
   public List<TelegramUser> retrieveAllActiveUsers() {
       return telegramUserRepository.findAllByActiveTrue();
   }

   @Override
   public Optional<TelegramUser> findByChatId(String chatId) {
       return telegramUserRepository.findById(chatId);
   }
}
ここでは、 Autowiredアノテーションとコンストラク ターを使用して、TelegramuserRepository オブジェクトの依存関係注入 (クラス インスタンスの導入) を使用していることに注意してください。これを変数に対して行うこともできますが、これは Spring Framework チームが推奨するアプローチです。

ボットの統計の追加

次に、/start コマンドと /stop コマンドを更新する必要があります。/start コマンドを使用する場合は、新しいユーザーをデータベースに保存し、active = true に設定する必要があります。/stop がある場合は、ユーザー データを更新します: active = false に設定します。StartCommandクラスを修正しましょう。
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Start {@link Command}.
*/
public class StartCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public final static String START_MESSAGE = "Привет. Я Javarush Telegram Bot. Я помогу тебе быть в курсе последних " +
           "статей тех авторов, котрые тебе интересны. Я еще маленький и только учусь.";

   public StartCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       String chatId = update.getMessage().getChatId().toString();

       telegramUserService.findByChatId(chatId).ifPresentOrElse(
               user -> {
                   user.setActive(true);
                   telegramUserService.save(user);
               },
               () -> {
                   TelegramUser telegramUser = new TelegramUser();
                   telegramUser.setActive(true);
                   telegramUser.setChatId(chatId);
                   telegramUserService.save(telegramUser);
               });

       sendBotMessageService.sendMessage(chatId, START_MESSAGE);
   }
}
ここでは、TelegramuserService オブジェクトもコンストラクターに渡し、これを使用して新しいユーザーを保存します。さらに、Java の Optional の利点を使用すると、次のロジックが機能します。データベースにユーザーがいる場合は、そのユーザーを単にアクティブにし、そうでない場合は、新しいアクティブなユーザーを作成します。停止コマンド:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.telegram.telegrambots.meta.api.objects.Update;

import java.util.Optional;

/**
* Stop {@link Command}.
*/
public class StopCommand implements Command {

   private final SendBotMessageService sendBotMessageService;
   private final TelegramUserService telegramUserService;

   public static final String STOP_MESSAGE = "Деактивировал все ваши подписки \uD83D\uDE1F.";

   public StopCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), STOP_MESSAGE);
       telegramUserService.findByChatId(update.getMessage().getChatId().toString())
               .ifPresent(it -> {
                   it.setActive(false);
                   telegramUserService.save(it);
               });
   }
}
同じ方法で TelegramServiceTest を StopCommand に渡します。追加のロジックは次のとおりです。そのようなチャット ID を持つユーザーがいる場合、それを非アクティブ化します。つまり、active = false に設定します。どうしたら自分の目でこれを見ることができますか?ボットの統計を表示する新しいコマンド /stat を作成しましょう。この段階では、これらはすべてのユーザーが利用できる単純な統計になります。今後は制限を設け、管理者のみがアクセスできるようにする予定です。統計には、アクティブなボット ユーザーの数というエントリが 1 つあります。これを行うには、値STAT("/stat")をCommandName に追加します。次に、StatCommandクラスを作成します。
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.telegram.telegrambots.meta.api.objects.Update;

/**
* Statistics {@link Command}.
*/
public class StatCommand implements Command {

   private final TelegramUserService telegramUserService;
   private final SendBotMessageService sendBotMessageService;

   public final static String STAT_MESSAGE = "Javarush Telegram Bot использует %s человек.";

   @Autowired
   public StatCommand(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {
       this.sendBotMessageService = sendBotMessageService;
       this.telegramUserService = telegramUserService;
   }

   @Override
   public void execute(Update update) {
       int activeUserCount = telegramUserService.retrieveAllActiveUsers().size();
       sendBotMessageService.sendMessage(update.getMessage().getChatId().toString(), String.format(STAT_MESSAGE, activeUserCount));
   }
}
ここではすべてが単純です。retrieveAllActiveUsersメソッド を使用してすべてのアクティブ ユーザーのリストを取得し、コレクションのサイズを取得します。また、必要な新しいサービスを渡すことを学習できるように、昇順クラスのCommandContainerJavarushTelegramBotを更新する必要もあります。コマンドコンテナ:
package com.github.javarushcommunity.jrtb.command;

import com.github.javarushcommunity.jrtb.service.SendBotMessageService;
import com.github.javarushcommunity.jrtb.service.TelegramUserService;
import com.google.common.collect.ImmutableMap;

import static com.github.javarushcommunity.jrtb.command.CommandName.*;

/**
* Container of the {@link Command}s, which are using for handling telegram commands.
*/
public class CommandContainer {

   private final ImmutableMap<String, Command> commandMap;
   private final Command unknownCommand;

   public CommandContainer(SendBotMessageService sendBotMessageService, TelegramUserService telegramUserService) {

       commandMap = ImmutableMap.<String, Command>builder()
               .put(START.getCommandName(), new StartCommand(sendBotMessageService, telegramUserService))
               .put(STOP.getCommandName(), new StopCommand(sendBotMessageService, telegramUserService))
               .put(HELP.getCommandName(), new HelpCommand(sendBotMessageService))
               .put(NO.getCommandName(), new NoCommand(sendBotMessageService))
               .put(STAT.getCommandName(), new StatCommand(sendBotMessageService, telegramUserService))
               .build();

       unknownCommand = new UnknownCommand(sendBotMessageService);
   }

   public Command retrieveCommand(String commandIdentifier) {
       return commandMap.getOrDefault(commandIdentifier, unknownCommand);
   }

}
ここでは、新しいコマンドをマップに追加し、それを TelegramUserService コンストラクターに渡しました。ただし、ボット自体では、コンストラクターのみが変更されます。
@Autowired
public JavarushTelegramBot(TelegramUserService telegramUserService) {
   this.commandContainer = new CommandContainer(new SendBotMessageServiceImpl(this), telegramUserService);
}
次に、TelegramUserService を引数として渡し、Autowired アノテーションを追加します。これは、アプリケーション コンテキストからそれを受け取ることを意味します。HelpCommandクラスも更新しましょうまた、説明に新しい統計コマンドが表示されるように

手動テスト

docker-compose-test.yml と JavarushTelegramBotApplication クラスの main メソッドからデータベースを起動しましょう。次に、一連のコマンドを作成します。
  • /stat - データベースが空の場合、このボットを使用する人はゼロになると予想されます。
  • /start - ボットを開始します。
  • /stat - ボットは 1 人によって使用されることが予想されます。
  • /stop - ボットを停止します。
  • /stat - 再び使用する人が 0 名になることが予想されます。
「Java プロジェクトの A から Z まで」: データベースに関連するすべてを追加します。 パート 2 - 2結果が同じであれば、機能は正しく動作しており、ボットは適切に動作していると言えます。何か問題が発生しても問題はありません。メイン メソッドをデバッグ モードで再起動し、パス全体を明確に調べてエラーの内容を見つけます。

テストを作成および更新します

コンストラクターを変更したため、テスト クラスも更新する必要があります。AbstractCommandTestクラスでは、もう 1 つのフィールド、 TelegramUserServiceクラスを追加する必要があります。これは 3 つのコマンドに必要です。
protected TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
次に、 CommandContainer のinit()メソッドを更新しましょう。
@BeforeEach
public void init() {
   SendBotMessageService sendBotMessageService = Mockito.mock(SendBotMessageService.class);
   TelegramUserService telegramUserService = Mockito.mock(TelegramUserService.class);
   commandContainer = new CommandContainer(sendBotMessageService, telegramUserService);
}
StartCommand でgetCommand()メソッド を更新する必要があります。
@Override
Command getCommand() {
   return new StartCommand(sendBotMessageService, telegramUserService);
}
また、StopCommand では次のようになります。
@Override
Command getCommand() {
   return new StopCommand(sendBotMessageService, telegramUserService);
}
次に、新しいテストを見てみましょう。StatCommandの典型的なテストを作成してみましょう。
package com.github.javarushcommunity.jrtb.command;

import static com.github.javarushcommunity.jrtb.command.CommandName.STAT;
import static com.github.javarushcommunity.jrtb.command.StatCommand.STAT_MESSAGE;

public class StatCommandTest extends AbstractCommandTest {
   @Override
   String getCommandName() {
       return STAT.getCommandName();
   }

   @Override
   String getCommandMessage() {
       return String.format(STAT_MESSAGE, 0);
   }

   @Override
   Command getCommand() {
       return new StatCommand(sendBotMessageService, telegramUserService);
   }
}
これは簡単です。次に、データベースの操作をテストする方法について説明します。これまでに行ったのは単体テストだけでした。 統合テストでは、アプリケーションの複数の部分間の統合をテストします。たとえば、アプリケーションやデータベースなどです。 ここでは、テストのためにデプロイされたデータベースが必要になるため、すべてがより複雑になります。したがって、テストをローカルで実行する場合は、docker-compose-test.yml からデータベースを実行する必要があります。このテストを実行するには、SpringBoot アプリケーション全体を実行する必要があります。テスト クラスには、アプリケーションを起動するSpringBootTestアノテーションが含まれています。しかし、アプリケーションが起動されると電報ボットも起動するため、このアプローチはうまくいきません。しかし、ここには矛盾があります。テストはマシン上でローカルに実行されるほか、GitHub Actions を通じてパブリックに実行されます。アプリケーション全体の起動でテストに合格するには、テレグラム ボット上の有効なデータ、つまり名前とトークンを使用してテストを実行する必要があります。 したがって、2 つのオプションがあります。
  1. したがって、ボットの名前とトークンを公開し、誰もそれを使用して私たちを妨害しないように、すべてがうまくいくことを願っています。
  2. 別の方法を考え出してください。
私は 2 番目のオプションを選択しました。SpringBoot テストにはDataJpaTestアノテーションがあります。これは、データベースをテストするときに必要なクラスのみを使用し、他のクラスはそのままにするために作成されました。しかし、電報ボットはまったく起動しないので、これは私たちにとっては都合がいいのです。これは、有効な名前とトークンを渡す必要がないことを意味します!))) Spring Data が実装するメソッドが期待どおりに機能することを確認するテストを取得します。ここで、テスト プロファイルの使用を指定するために@ActiveProfiles("test")アノテーションを使用していることに注意することが重要です。これはまさに、データベースの正しいプロパティをカウントできるようにするために必要なものです。テストを実行する前にデータベースを準備しておくとよいでしょう。この問題には、次のようなアプローチがあります。SQL アノテーションをテストに追加し、テストを開始する前に実行する必要があるスクリプト名のコレクションを渡します。
@Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
私たちの場合、それらはパス ./src/test/resources/ + アノテーションで指定されたパスに沿って配置されます。見た目は次のとおりです。
clearDbs.sql:
DELETE FROM tg_user;

telegram_users.sql:
INSERT INTO tg_user VALUES ("123456789", 1);
INSERT INTO tg_user VALUES ("123456788", 1);
INSERT INTO tg_user VALUES ("123456787", 1);
INSERT INTO tg_user VALUES ("123456786", 1);
INSERT INTO tg_user VALUES ("123456785", 1);
INSERT INTO tg_user VALUES ("123456784", 0);
INSERT INTO tg_user VALUES ("123456782", 0);
INSERT INTO tg_user VALUES ("123456781", 0);
TelegramUserRepositoryIT テストの結果は次のようになります (ご覧のとおり、統合テストの名前は異なります。Test ではなく IT を追加します)。
package com.github.javarushcommunity.jrtb.repository;

import com.github.javarushcommunity.jrtb.repository.entity.TelegramUser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.jdbc.Sql;

import java.util.List;
import java.util.Optional;

import static org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace.NONE;

/**
* Integration-level testing for {@link TelegramUserRepository}.
*/
@ActiveProfiles("test")
@DataJpaTest
@AutoConfigureTestDatabase(replace = NONE)
public class TelegramUserRepositoryIT {

   @Autowired
   private TelegramUserRepository telegramUserRepository;

   @Sql(scripts = {"/sql/clearDbs.sql", "/sql/telegram_users.sql"})
   @Test
   public void shouldProperlyFindAllActiveUsers() {
       //when
       List<TelegramUser> users = telegramUserRepository.findAllByActiveTrue();

       //then
       Assertions.assertEquals(5, users.size());
   }

   @Sql(scripts = {"/sql/clearDbs.sql"})
   @Test
   public void shouldProperlySaveTelegramUser() {
       //given
       TelegramUser telegramUser = new TelegramUser();
       telegramUser.setChatId("1234567890");
       telegramUser.setActive(false);
       telegramUserRepository.save(telegramUser);

       //when
       Optional<TelegramUser> saved = telegramUserRepository.findById(telegramUser.getChatId());

       //then
       Assertions.assertTrue(saved.isPresent());
       Assertions.assertEquals(telegramUser, saved.get());
   }
}
テストを作成しましたが、GitHub で CI プロセスを起動するとどうなるのかという疑問が生じます。データベースは持たないでしょう。今のところ、実際には赤いビルドだけが存在します。これを行うには、ビルドの起動を構成できる GitHub アクションがあります。テストを実行する前に、必要な設定を使用してデータベース起動を追加する必要があります。結局のところ、インターネット上にはサンプルがあまりないので、これをどこかに保存しておくことをお勧めします。.github/workflows/maven.yml ファイルを更新しましょう。
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven

name: Java CI with Maven

on:
 push:
   branches: [ main ]
 pull_request:
   branches: [ main ]

jobs:
 build:
   runs-on: ubuntu-latest
   steps:
   - uses: actions/checkout@v2
   - name: Set up MySQL
     uses: mirromutth/mysql-action@v1.1
     with:
       mysql version: '5.7'
       mysql database: 'dev_jrtb_db'
       mysql root password: 'root'
       mysql user: 'dev_jrtb_db_user'
       mysql password: 'dev_jrtb_db_password'
   - name: Set up JDK 1.11
     uses: actions/setup-java@v1
     with:
       java-version: 1.11
   - name: Build with Maven
     run: mvn -B package --file pom.xml
新しいSet up MySQLブロックが追加されました。ブロックが追加されました。その中で、MySQL を CI プロセスに追加し、同時に必要な変数を定義します。これで、必要なものがすべて追加されました。最後の段階では、変更をプッシュし、ビルドが合格してグリーンになることを確認します。

ドキュメントの更新

pom.xml でプロジェクトのバージョンを 0.3.0-SNAPSHOT から 0.4.0-SNAPSHOT に更新し、RELEASE_NOTES にも追加しましょう。
## 0.4.0-SNAPSHOT

*   JRTB-1: added repository layer.
これらすべてが完了したら、コミット、プッシュ、プル リクエストを作成します。そして最も重要なことは、私たちのビルドは環境に優しいことです。「Java プロジェクトの A から Z まで」: データベースに関連するすべてを追加します。 パート 2 ~ 3

役立つリンク:

すべての変更は、作成されたプル リクエストで確認できます。読んでくれた皆さん、ありがとう。

シリーズのすべてのマテリアルのリストは、この記事の冒頭にあります。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION