[英]Spring: How to set system properties in integration test when @ComponentScan is used?
摘要:在我的应用程序类中添加@ComponentScan
(或@SpringBootApplication
)批注会更改SpringApplicationBuilder.properties()
的行为并破坏我的集成测试。
我正在使用Spring Boot示例的简化版本: spring-boot-sample-websocket-jetty
除了“ echo”示例所需的内容之外,我已经删除了所有内容(并且我正在使用Spring Boot 1.3.3)。
我剩下以下SampleJettyWebSocketsApplication
代码:
@Configuration
@EnableAutoConfiguration
//@ComponentScan // --- If I uncomment this the test breaks ---
@EnableWebSocket
public class SampleJettyWebSocketsApplication
implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoWebSocketHandler(), "/echo").withSockJS();
}
@Bean
public EchoService echoService() {
return new DefaultEchoService("Did you say \"%s\"?");
}
@Bean
public WebSocketHandler echoWebSocketHandler() {
return new EchoWebSocketHandler(echoService());
}
public static void main(String[] args) {
SpringApplication.run(SampleJettyWebSocketsApplication.class, args);
}
}
和以下测试类(直接来自Spring Boot示例的代码):
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SampleJettyWebSocketsApplication.class)
@WebIntegrationTest({"server.port=0"})
@DirtiesContext
public class SampleWebSocketsApplicationTests {
private static Log logger = LogFactory.getLog(SampleWebSocketsApplicationTests.class);
@Value("${local.server.port}")
private int port = 1234;
@Test
public void echoEndpoint() throws Exception {
logger.info("Running the echoEndpoint test. Port: " + port + ". Path: /echo/websocket");
ConfigurableApplicationContext context = new SpringApplicationBuilder(
ClientConfiguration.class, PropertyPlaceholderAutoConfiguration.class)
.properties("websocket.uri:ws://localhost:" + this.port
+ "/echo/websocket")
.run("--spring.main.web_environment=false");
long count = context.getBean(ClientConfiguration.class).latch.getCount();
AtomicReference<String> messagePayloadReference = context
.getBean(ClientConfiguration.class).messagePayload;
context.close();
assertThat(count).isEqualTo(0);
assertThat(messagePayloadReference.get())
.isEqualTo("Did you say \"Hello world!\"?");
}
@Configuration
static class ClientConfiguration implements CommandLineRunner {
@Value("${websocket.uri}")
private String webSocketUri;
private final CountDownLatch latch = new CountDownLatch(1);
private final AtomicReference<String> messagePayload = new AtomicReference<String>();
@Override
public void run(String... args) throws Exception {
logger.info("Waiting for response: latch=" + this.latch.getCount());
if (this.latch.await(10, TimeUnit.SECONDS)) {
logger.info("Got response: " + this.messagePayload.get());
}
else {
logger.info("Response not received: latch=" + this.latch.getCount());
}
}
@Bean
public WebSocketConnectionManager wsConnectionManager() {
logger.info("Setting up SimpleClientWebSocketHandler...");
WebSocketConnectionManager manager = new WebSocketConnectionManager(client(),
handler(), this.webSocketUri);
manager.setAutoStartup(true);
return manager;
}
@Bean
public StandardWebSocketClient client() {
return new StandardWebSocketClient();
}
@Bean
public SimpleClientWebSocketHandler handler() {
logger.info("Creating new SimpleClientWebSocketHandler using SimpleGreetingService...");
return new SimpleClientWebSocketHandler(greetingService(), this.latch,
this.messagePayload);
}
@Bean
public GreetingService greetingService() {
return new SimpleGreetingService();
}
}
}
像上面那样运行应用程序和单元测试都很好, 但是如果我取消注释应用程序类上的@ComponentScan
批注,则应用程序仍然可以正常运行,但是测试因以下错误而中断:
Could not resolve placeholder 'websocket.uri' in string value "${websocket.uri}"
。
我已经阅读了在springapplicationbuilder上设置运行时属性的内容 :
您在SpringApplicationBuilder上配置的属性在应用程序的环境中可用,而不是系统属性。
并在@ComponentScan
javadoc中:
如果未定义特定的程序包,则将从声明此批注的类的程序包中进行扫描。
但是我不明白为什么添加@ComponentScan
批注后行为会发生变化。
使用@ComponentScan
(或@SpringBootApplication
)注释应用程序类时,如何在测试中设置系统属性websocket.uri
?
(我的目标是使用@SpringBootApplication
,它包含@ComponentScan
,但是直到我能使用它时我才能这样做。)
添加我的想法(从我可以从您的代码中收集的所有信息):
-尝试在应用程序属性中添加属性websocket.uri,或者如果您的项目包含src / test / resources / test.properties,则将其添加到test.properties文件中。@ ComponentScan应该将其选中。
-否则,你只能说:
public static void main(String[] args) {
System.setProperty("websocket.uri","<your uri>");
SpringApplication.run(SampleJettyWebSocketsApplication.class, args);
}
希望能帮助到你。
有几种添加系统属性的方法。
解决方案1:以-Dabc=xyz
格式添加Test
参数,这会将属性abc
添加到系统属性中。
解决方案2:就像0楼一样。
解决方案3:只需让spring-boot
加载诸如classpath:bootstrap.yml
的属性,就可以在其中指定任何属性。
注释@ComponentScan
将启用基于当前包或ComponentScan#basePackages
自动扫描。 这意味着将对SampleWebSocketsApplicationTests.ClientConfiguration
进行扫描,因为它们具有相同的基本包samples.websocket.jetty
。
然而, SampleWebSocketsApplicationTests.ClientConfiguration
不应该被解析SpringJUnit4ClassRunner
因为我们需要分析它SampleWebSocketsApplicationTests#echoEndpoint
手动。 它只能由echoEndpoint()
创建的ApplicationContext
进行解析。
此外, @SpringBootApplication
等于将@Configuration
和@EnableAutoConfiguration
和@ComponentScan
一起使用,因此注释掉@ComponentScan
或@SpringBootApplication
将具有相同的效果。
我的建议是举类SampleWebSocketsApplicationTests
成包samples.websocket.jettytest
(来自不同samples.websocket.jetty
),并启用@ComponentScan
或@SpringBootApplication
上SampleJettyWebSocketsApplication
,然后再试一次。 它应该工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.