我開發了一個系統,其基礎架構層是在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
類包含的領域和基礎設施豆類聲明,以他們做了Spring上下文。
本課程是在src/test/java
和datasource.properties
文件以及測試.sql在src/test/resources
。測試類運行良好,運行測試腳本,創建表,但是當Repository在測試期間查找某些數據時,它將搜索MySQL而不是HSQLDB。這是一個測試類:
@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());
}
}
我驗證了這一點,當我用的是隻存在於測試數據庫,並得到了403
狀態,而與MySQL值了200
狀態的用戶名和密碼。 似乎在編寫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=
DB依賴在pom.xml中:
<!-- 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>
執行失敗失敗的原因是什麼?使用註釋?爲dev和測試創建.properties,並使用BDs conf和主要.properties與spring.profiles.active = dev/test
在配置文件之間切換?我想提出一些建議。
感謝。在github上
項目鏈接:https://github.com/augustodossantosti/librarymanager-jwtauth
我認爲它更好地使用不同的屬性爲不同的環境,以避免這種混淆。 application-test.properties,application-prod.properties – CrazyMac
您正在使它變得複雜...只需提供一個單獨的屬性文件進行測試,其中包含hsqldb的信息,加載該文件以覆蓋其他屬性...使用框架不反對它。此外,您不應該爲每個測試重新創建數據庫,進行測試'@ Transactional',並在測試完成後將所有內容回滾。節省您很多時間。 –
感謝您的建議。實際上,使用框架是最好的選擇。 –