インフラストラクチャ層がSpringブート(セキュリティ、データJPA、MVC ...)で開発されたシステムを開発しました。実行時に、システムはMySQLに接続し、その設定はsrc/main/resources/application.properties
と、認証のためのユーザーの挿入とロールを含む.sqlになります。
統合テストでは、HSQLDBを使用してデータを分離し、安全なテストを実行することに決めました。このために、コントローラからテストするテーブルとメソッドを作成してクリーンアップするメソッドを含むクラスAbstractIntegrationTest
を作成しました。すべてのテストクラスは、それを拡張します。(私はデータベースを伴わない方法を隠されてきた)スプリングブートアプリケーションでの統合テストのためのメモリ内データベース構成(HSQLDB)
@WebAppConfiguration
@ContextConfiguration(classes={LibraryManagerContextConfiguration.class, WebSecurityConfig.class})
public class AbstractIntegrationTest {
@Autowired
private WebApplicationContext webApplicationContext;
@Autowired
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Autowired
private LoginFilter loginFilter;
private MockMvc mockMvc;
private static IDatabaseConnection databaseConnection;
private static Connection connection;
private static boolean isAfterFirstRun;
private static Logger logger = LogManager.getLogger(AbstractIntegrationTest.class);
@BeforeClass
public static void createDatabase() throws Exception {
try {
final Properties properties = loadProperties();
final String driver = properties.getProperty("datasource.driver");
final String url = properties.getProperty("datasource.url");
final String userName = properties.getProperty("datasource.username");
final String password = properties.getProperty("datasource.password");
final String schema = properties.getProperty("datasource.schema");
Class.forName(driver);
connection = DriverManager.getConnection(url, userName, password);
databaseConnection = new HsqldbConnection(connection, schema);
} catch (final SQLException exception) {
throw new RuntimeException(exception.getMessage(), exception);
} catch (final ClassNotFoundException exception) {
throw new RuntimeException(exception.getMessage(), exception);
}
}
@Before
public void setDatabaseUp() throws Exception {
if (!isAfterFirstRun) {
runSQLCommands(getDataSetupFile());
}
runSQLCommands(getClearDatabaseFile());
runSQLCommands(getResetSequencesFile());
runSQLCommands(getDataFile());
isAfterFirstRun = true;
}
@AfterClass
public static void closeConnection() throws Exception {
connection.close();
databaseConnection.close();
}
protected void runSQLCommands(final String file) throws Exception {
if (file != null) {
final InputStream stream = getSQLInputStream(file);
final BufferedReader databaseReader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
int i = 1;
String sqlStatement = null;
while ((sqlStatement = databaseReader.readLine()) != null) {
if (sqlStatement.startsWith("--")) {
i++;
continue;
}
final int index = sqlStatement.lastIndexOf(";");
if (index > -1) {
sqlStatement = sqlStatement.substring(0, index + 1);
}
if (sqlStatement.trim().length() != 0) {
try {
connection.createStatement().execute(sqlStatement);
logger.info(sqlStatement);
} catch (final Exception exception) {
logger.error("Error running command on line " + i + " of file " + file + ": " + exception.getMessage());
throw new RuntimeException(exception);
}
}
i++;
}
}
}
protected IDatabaseConnection getConnection() {
return databaseConnection;
}
protected static IDataSet getDataSet(final String dataset) {
try {
final InputSource source = new InputSource(AbstractIntegrationTest.class.getResourceAsStream(dataset));
return new FlatXmlDataSetBuilder().build(source);
} catch (final Exception exception) {
throw new RuntimeException("Cannot read the dataset file " + dataset + "!", exception);
}
}
private static Properties loadProperties() throws Exception {
final InputStream stream = ClassLoader.getSystemResourceAsStream("datasource.properties");
if (stream == null) {
throw new FileNotFoundException("File erm.properties not found. A file named erm.properties must be present "
+ "in the src/test/resources folder of the project whose class is being tested.");
}
final Properties properties = new Properties();
properties.load(stream);
return properties;
}
private static InputStream getSQLInputStream(final String fileName) {
return AbstractIntegrationTest.class.getResourceAsStream(fileName);
}
protected String getClearDatabaseFile() {
return "/database/clear-database.sql";
}
protected String getDataSetupFile() {
return "/database/database-setup.sql";
}
protected String getDataFile() {
return "/database/data.sql";
}
protected String getResetSequencesFile() {
return "/database/reset-sequences.sql";
}
}
彼らは春のコンテキストを構成しているので、LibraryManagerContextConfiguration
とWebSecurityConfig
クラスは、ドメインやインフラ豆の宣言を含みます。
このクラスは、src/test/java
であり、datasource.properties
ファイルは、テスト.sqlと共にsrc/test/resources
です。テストクラスは完全に実行され、テストスクリプトが実行され、テーブルが作成されますが、テスト中にリポジトリがデータを検索すると、HSQLDBではなくMySQLが検索されます。ここではテストクラスです:
@RunWith(SpringJUnit4ClassRunner.class)
public class AuthenticationIntegrationTest extends AbstractIntegrationTest {
@Test
public void shouldGetAuthorizationJwt() throws Exception {
final String jsonCredentials = "{"
+ "\"username\" : \"augusto\","
+ "\"password\" : \"spring\""
+ "}";
final MvcResult result = performRESTLogin(jsonCredentials);
final MockHttpServletResponse response = result.getResponse();
final int status = response.getStatus();
final String jwt = response.getHeader("Authorization");
assertThat(status, is(200));
assertThat(jwt, notNullValue());
}
}
私は唯一のテスト・データベースに存在していたとMySQL値が200
のステータスを得て、一方、403
のステータスを持ったユーザ名とパスワードを使用したとき、私はこれを検証しました。 HSQLDBの準備後、mainの.propertiesと.sqlが読み込まれ、使用されているデータベースの設定を上書きするようです。
application.properties:
server.contextPath=/librarymanager
server.port: 8081
spring.datasource.url = jdbc:mysql://localhost:3306/librarymanager
spring.datasource.username = root
spring.datasource.password = root
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create-drop
spring.jpa.hibernate.naming.strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
datasource.properties:
datasource.class=org.hsqldb.jdbc.JDBCDataSource
datasource.driver=org.hsqldb.jdbc.JDBCDriver
datasource.url=jdbc:hsqldb:mem:librarymanager;sql.syntax_ora=true
datasource.schema=sa
datasource.username=sa
datasource.password=
のpom.xmlにDB依存性:
<!-- Banco de dados -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
実行に成功するために欠けているものは何ですか?注釈の使用?開発者用の.propertiesを作成し、BD confと別のテストを行い、メインの.propertiesにspring.profiles.active = dev/test
を付けてプロファイルを切り替えますか?私はいくつかの提案をしたいと思います。
ありがとうございました。 githubの中
プロジェクトリンク:提案のためhttps://github.com/augustodossantosti/librarymanager-jwtauth
この混乱を避けるために、さまざまな環境で異なるプロパティを使用する方が良いと思います。 application-test.properties、application-prod.properties – CrazyMac
あなたは複雑になっています...テストのために、hsqldbの情報を含む別のプロパティファイルを提供し、他のプロパティを上書きするためにロードします。フレームワークはそれに対して反対ではありません。また、テストごとにデータベースを作り直したり、テストを '@ Transactional'にしたり、テスト終了後にすべてをロールバックしたりするべきではありません。あなたに多くの時間を節約します。 –
提案していただきありがとうございます。実際にフレームワークを使って作業するのが最善の選択肢です。 –