Spring-Boot-Mvc-Webアプリケーションのapplication.properties
ファイルには、次のデータベース構成があります。
spring.datasource.url=jdbc:h2:tcp://localhost/~/pdk
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
これは私が作った唯一の設定です。私が作った他の設定はどこにもありません。それにもかかわらず、Springとサブシステムは、各Webアプリケーションの実行で自動的にデータベースを再作成します。データベースは、アプリケーションの終了後にデータが含まれている間、つまりシステム実行時に再作成されます。
私はこのデフォルトを理解しておらず、これがテストに適していると期待していました。
しかし、テストを実行し始めたとき、データベースが1回だけ再作成されることがわかりました。テストは事前定義された順序で実行されないため、これはまったく無意味です。
したがって、質問は次のとおりです。 意味を成す方法は?つまり. アプリケーションの最初の起動時に行われる各テストの前にデータベースを再作成する方法は?
私のテストクラスヘッダーは次のとおりです。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = myapp.class)
//@WebAppConfiguration
@WebIntegrationTest
@DirtiesContext
public class WebControllersTest {
ご覧のとおり、クラスレベルで@DirtiesContext
を試しましたが、役に立ちませんでした。
UPDATE
私は豆を持っています
@Service
public class DatabaseService implements InitializingBean {
メソッドを持っています
@Override
@Transactional()
public void afterPropertiesSet() throws Exception {
log.info("Bootstrapping data...");
User user = createRootUser();
if(populateDemo) {
populateDemos();
}
log.info("...Bootstrapping completed");
}
データベースからすべてのデータを消去するpopulateDemos()
メソッドを作成しました。残念ながら、@DirtiesContext
にもかかわらず、各テストの前には呼び出されません。どうして?
実際、これが欲しいと思う:
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
@DirtiesContextは、同じクラス内でクラスレベルおよびメソッドレベルのアノテーションとして使用できます。このようなシナリオでは、ApplicationContextは、そのような注釈付きメソッドの後、およびクラス全体の後にダーティとしてマークされます。 DirtiesContext.ClassModeがAFTER_EACH_TEST_METHODに設定されている場合、コンテキストはクラス内の各テストメソッドの後にダーティとしてマークされます。
データベースを作成するには、spring.jpa.hibernate.ddl-auto=create-drop
を使用して他の回答を行う必要があります。ここで、各テストでデータベースを作成することが目的の場合、springは非常に便利な注釈を提供します
@Transactional(value=JpaConfiguration.TRANSACTION_MANAGER_NAME)
@Sql(executionPhase=ExecutionPhase.BEFORE_TEST_METHOD,scripts="classpath:/test-sql/group2.sql")
public class GroupServiceTest extends TimeoffApplicationTests {
これはこのパッケージorg.springframework.test.context.jdbc.Sql;
からのもので、テスト前メソッドとテスト後メソッドを実行できます。データベースにデータを入力します。
毎回データベースを作成することに関して、テストにはcreate-dropオプションのみが必要であり、このアノテーションを使用してカスタムプロパティを使用してテストを構成できるとします
@TestPropertySource(locations="classpath:application-test.properties")
public class TimeoffApplicationTests extends AbstractTransactionalJUnit4SpringContextTests{
それが役に立てば幸い
スプリングブートでは、テストごとにh2データベースを一意に定義できます。各テストのデータソースURLをオーバーライドするだけです
@SpringBootTest(properties = {"spring.config.name=myapp-test-h2","myapp.trx.datasource.url=jdbc:h2:mem:trxServiceStatus"})
テストは並行して実行できます。
テスト内でデータをリセットするには
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
spring.jpa.hibernate.ddl-auto=create-drop
を使用する場合、データベースを作成/削除するには十分ですか?
何らかの種類のSpring-Data統合を使用していない限り(これはまったくわかりません)、これは自分で実装する必要があるカスタムロジックのようです。 Springは、データベース、そのスキーマ、およびテーブルについては知りません。
JUnitを想定して、適切な@Before
および@After
メソッドを記述して、データベース、そのテーブル、およびデータをセットアップおよびクリーンアップします。テスト自体が必要なデータを書き込むことができ、必要に応じてテスト後に潜在的にクリーンアップできます。
@DirtiesContext
の代替を探している場合は、以下のコードが役立ちます。 this answer のコードを使用しました。
最初に、テストリソースフォルダーのapplication.yml
ファイルでH2データベースをセットアップします。
spring:
datasource:
platform: h2
url: jdbc:h2:mem:test
driver-class-name: org.h2.Driver
username: sa
password:
その後、ResetDatabaseTestExecutionListener
というクラスを作成します。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.TestContext;
import org.springframework.test.context.support.AbstractTestExecutionListener;
import javax.sql.DataSource;
import Java.sql.Connection;
import Java.sql.ResultSet;
import Java.sql.SQLException;
import Java.sql.Statement;
import Java.util.HashSet;
import Java.util.Set;
public class ResetDatabaseTestExecutionListener extends AbstractTestExecutionListener {
@Autowired
private DataSource dataSource;
public final int getOrder() {
return 2001;
}
private boolean alreadyCleared = false;
@Override
public void beforeTestClass(TestContext testContext) {
testContext.getApplicationContext()
.getAutowireCapableBeanFactory()
.autowireBean(this);
}
@Override
public void prepareTestInstance(TestContext testContext) throws Exception {
if (!alreadyCleared) {
cleanupDatabase();
alreadyCleared = true;
}
}
@Override
public void afterTestClass(TestContext testContext) throws Exception {
cleanupDatabase();
}
private void cleanupDatabase() throws SQLException {
Connection c = dataSource.getConnection();
Statement s = c.createStatement();
// Disable FK
s.execute("SET REFERENTIAL_INTEGRITY FALSE");
// Find all tables and truncate them
Set<String> tables = new HashSet<>();
ResultSet rs = s.executeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='PUBLIC'");
while (rs.next()) {
tables.add(rs.getString(1));
}
rs.close();
for (String table : tables) {
s.executeUpdate("TRUNCATE TABLE " + table);
}
// Idem for sequences
Set<String> sequences = new HashSet<>();
rs = s.executeQuery("SELECT SEQUENCE_NAME FROM INFORMATION_SCHEMA.SEQUENCES WHERE SEQUENCE_SCHEMA='PUBLIC'");
while (rs.next()) {
sequences.add(rs.getString(1));
}
rs.close();
for (String seq : sequences) {
s.executeUpdate("ALTER SEQUENCE " + seq + " RESTART WITH 1");
}
// Enable FK
s.execute("SET REFERENTIAL_INTEGRITY TRUE");
s.close();
c.close();
}
}
上記のコードはデータベースをリセットし(テーブルの切り捨て、シーケンスのリセットなど)、H2データベースで動作するように準備されます。別のメモリデータベース(HsqlDBなど)を使用している場合は、SQLクエリで必要な変更を行って同じことを達成する必要があります。
その後、テストクラスに移動して、次のような@TestExecutionListeners
注釈を追加します。
@TestExecutionListeners(mergeMode =
TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
listeners = {ResetDatabaseTestExecutionListener.class}
)
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CreateOrderIT {
これは動作するはずです。
このアプローチと@DirtiesContext
のパフォーマンスに違いがない場合、 おそらく テスト内で@MockBean
を使用しているため、コンテキストをダーティとしてマークし、Springコンテキストを自動的にリロードします。 。