如何在junit @Value
定义中使用@Rule
弹簧注入属性?
背景:我想使用FakeSftpServerRule
用嵌入式内存sftp服务器创建一个junit测试。
问题:在插入@Rule
字段之前执行了@Value
。
@Value("${ftp.port}")
private Integer port;
@Value("${ftp.user}")
private String user;
@Value("${ftp.pass}")
private String pass;
@Rule
public final FakeSftpServerRule sftpServer = new FakeSftpServerRule().setPort(port).addUser(user, pass);
答案 0 :(得分:1)
解决您的问题的一种方法是初始化Spring上下文并自己执行属性查找,如我的初始评论和referencing to a sample所阐明的那样。
现在的问题是,如果不注意,最终可能会两次初始化Spring上下文,一次是使用静态定义,一次是使用常规的Spring测试设置。
幸运的是,Spring本身带有AbstractJUnit4SpringContextTests支持类,允许您重用已经加载的Spring ApplicationContext。
我们现在可以利用此功能来初始化伪造的SFTP服务器,还可以将bean注入测试代码中,而无需通过context.getBean(...)
调用进行手动查找。
下面的代码应使您了解如何完成此操作:
@ContextConfiguration(classes = SpringTest.Config.class)
public class SpringTest extends AbstractJUnit4SpringContextTests {
@Configuration
@PropertySource("classpath:some.properties")
static class Config {
@Bean(name = "namedBean")
String someBean() {
return "Test";
}
@Bean
UUID uuidGenerator() {
return UUID.randomUUID();
}
}
static ApplicationContext context;
static int port;
static String user;
static String pass;
static {
context = new AnnotationConfigApplicationContext(SpringTest.Config.class);
Environment env = context.getBean(Environment.class);
String sPort = env.getProperty("port");
port = Integer.parseInt(sPort);
user = env.getProperty("user");
pass = env.getProperty("pass");
}
@Autowired
private UUID uuidGenerator;
public SpringTest() {
// reuse the already initialized Spring application context
setApplicationContext(context);
}
@Rule
public final FakeSftpServerRule sftpServer =
new FakeSftpServerRule().setPort(port).addUser(user, pass);
@Test
public void test() {
String someBean = context.getBean("namedBean", String.class);
System.out.println(someBean);
System.out.println(uuidGenearator.toString());
System.out.println(sftpServer.getPort());
}
}
一种可能更优雅的方法是在Spring配置中定义如下内容:
@Configuration
@PropertySource("classpath:some.properties")
@EnableConfigurationProperties(SftpSettings.class)
static class Config {
...
}
其中SftpSettings
是一个简单的bean类,例如
@Validated
@Getter
@Setter
@ConfigurationProperties(prefix="sftp")
public class SftpSettings {
@NotNull
private int port;
@NotNull
private String user;
@NotNull
private String pass;
}
,然后在SftpSettings
而非Environment
上执行查找:
static {
context = new AnnotationConfigApplicationContext(SpringTest.Config.class);
SftpSettings settings = context.getBean(SftpSettings.class);
port = settings.getPort();
user = settings.getUser();
pass = settings.getPass();
}
这样,Spring将负责从属性文件中查找值,并将这些值转换为适当的格式。
答案 1 :(得分:0)
您可以在方法上使用 @Rule
注释,该方法在值注入后执行。至少 SpringJUnit4ClassRunner
的情况似乎是这样。
@Value("${ftp.port}")
private Integer port;
@Value("${ftp.user}")
private String user;
@Value("${ftp.pass}")
private String pass;
@Rule
public FakeSftpServerRule getFakeSftpServerRule() {
return new FakeSftpServerRule().setPort(port).addUser(user, pass);
}
请注意,如果您的规则同时实现了 TestRule
和 MethodRule
接口,则该方法可能会被选取并执行两次,这可能会导致一些问题。为避免这种情况,请将方法的返回类型更改为 TestRule
。
@Rule
public TestRule getFakeSftpServerRule() {
return new FakeSftpServerRule().setPort(port).addUser(user, pass);
}