應用程式在開發時會設定自己的相關資源,例如開發用的資料庫,測試的環境中也會使用自己的資源,上線之後又會是另一個,雖然說,轉移至不同情境時,修改一下設定檔也可以應付,然而,如果必須修改的項目很多,也是蠻麻煩的。
為了要能使用記憶體內嵌資料庫,以及稍後可以進行單元測試,可以在 build.gradle 中加入 org.springframework:spring-jdbc
與 org.springframework:spring-test
:
apply plugin: 'java-library'
repositories {
jcenter()
}
dependencies {
testImplementation 'junit:junit:4.12'
testImplementation 'org.springframework:spring-test:5.1.2.RELEASE'
compile 'com.h2database:h2:1.4.196'
compile 'org.springframework:spring-context:5.1.2.RELEASE'
compile 'org.springframework:spring-jdbc:5.1.2.RELEASE'
}
你可以使用 @Profile
來標註 Bean 的使用環境,例如,在測試時使用記憶體內嵌資料庫:
package cc.openhome;
import javax.sql.DataSource;
import org.h2.jdbcx.JdbcDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
public class AppConfig {
@Value("${cc.openhome.jdbcUrl}")
private String jdbcUrl;
@Value("${cc.openhome.user}")
private String user;
@Value("${cc.openhome.password}")
private String password;
@Profile("dev")
@Bean
public DataSource getDataSource() {
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
return dataSource;
}
@Profile("test")
@Bean(destroyMethod="shutdown")
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:testData.sql")
.build();
}
@Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
在這邊看到兩個 Bean 都傳回 DataSource
,而這兩個 Bean 分別標示為 "dev"
與 "test"
,可以藉由在執行 JVM 時加上 -Dspring.profiles.active=test
(或者是設定環境變數 JAVA_OPTIONS="-Dspring.profiles.active=test"
)來選擇使用哪個 Bean。
在進行單元測試時,可以使用 @ActiveProfiles
來指定要使用的 Profile。例如:
package test.cc.openhome;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cc.openhome.AppConfig;
import cc.openhome.model.UserService;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
@ActiveProfiles("test")
public class MainTest {
@Autowired
private UserService userService;
@Test public void testMain() {
userService.messages("caterpillar")
.forEach(message -> {
assertEquals("username should return 'caterpillar'",
"caterpillar", message.getUsername());
});
}
}
單元測試時,可以使用 @RunWith
指定使用 Spring 實作的 Runner,@ContextConfiguration
指定設定檔來源,如此 Spring 就可以自動綁定想要的 Bean 元件,而 @ActiveProfiles
可以指定要使用的 Profile。
你可以在 SpringDI3 找到上面這個範例專案。