Junit 테스트를 사용하여 명령줄 인수를 Spring Boot 응용 프로그램에 전달
저는 매우 기본적인 Spring Boot 애플리케이션을 가지고 있는데, 이것은 명령줄에서 인수를 예상하고 있지만, 그렇지 않으면 작동하지 않습니다.여기 코드가 있습니다.
@SpringBootApplication
public class Application implements CommandLineRunner {
private static final Logger log = LoggerFactory.getLogger(Application.class);
@Autowired
private Reader reader;
@Autowired
private Writer writer;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
Assert.notEmpty(args);
List<> cities = reader.get("Berlin");
writer.write(cities);
}
}
이것은 저의 Junit 시험 수업입니다.
@RunWith(SpringRunner.class)
@SpringBootTest
public class CityApplicationTests {
@Test
public void contextLoads() {
}
}
지금이다,Assert.notEmpty()
논쟁을 통과시키기 위한 명령하지만 지금은 같은 것을 위해 Junit test를 쓰고 있습니다.하지만, 저는 다음과 같은 예외 인상을 받았습니다.Assert
.
2016-08-25 16:59:38.714 ERROR 9734 --- [ main] o.s.boot.SpringApplication : Application startup failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:801) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:782) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:769) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:111) [spring-boot-test-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.test.autoconfigure.AutoConfigureReportTestExecutionListener.prepareTestInstance(AutoConfigureReportTestExecutionListener.java:46) [spring-boot-test-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:228) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:287) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:289) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:247) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) [spring-test-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na]
Caused by: java.lang.IllegalArgumentException: [Assertion failed] - this array must not be empty: it must contain at least 1 element
at org.springframework.util.Assert.notEmpty(Assert.java:222) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.util.Assert.notEmpty(Assert.java:234) ~[spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at com.deepakshakya.dev.Application.run(Application.java:33) ~[classes/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
... 32 common frames omitted
어떻게 매개변수를 전달할 수 있을까요?
@SpringBootTest
가지다args
param. 거기에 cli 인수를 전달할 수 있습니다.
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html#args-- 을 참조하십시오.
테스트에서 ApplicationContext를 주입하고 필요한 매개 변수를 사용하여 CommandLineRunner를 호출함으로써 SpringBoot에서 제대로 작동하는 Junit 테스트를 생성할 수 있는 방법을 찾았습니다.
최종 코드는 다음과 같습니다.
package my.package.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
class AsgardBpmClientApplicationIT {
@Autowired
ApplicationContext ctx;
@Test
public void testRun() {
CommandLineRunner runner = ctx.getBean(CommandLineRunner.class);
runner.run ( "-k", "arg1", "-i", "arg2");
}
}
유감스럽게도 귀사의 솔루션은 귀하가 제시한 방식으로 작동하지 않을 것입니다(Spring에 대한 자체 테스트 프레임워크를 구현하기 전까지는).
이는 검정을 실행할 때 봄(검정)이SpringBootContextLoader
보다 구체적으로) 고유한 방식으로 응용 프로그램을 실행합니다.그것은 예를 들어,SpringApplication
호출합니다.run
인수가 없는 메서드입니다.또한 사용하지 않습니다.main
응용 프로그램에서 구현된 메서드입니다.
그러나 응용프로그램을 테스트할 수 있도록 응용프로그램을 재팩터링할 수 있습니다.
(스프링을 사용하고 있기 때문에) 가장 쉬운 솔루션은 순수한 명령줄 인수 대신 스프링 구성 속성을 사용하여 구현할 수 있다고 생각합니다. (그러나 이 솔루션은 스프링의 주요 목적이기 때문에 "구성 인수"에 사용되어야 한다는 것을 알아야 합니다.)configuration properties
메커니즘)
다음을 사용하여 매개 변수 읽기@Value
주석:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Value("${myCustomArgs.customArg1}")
private String customArg1;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
Assert.notNull(customArg1);
//...
}
}
표본 검정:
@RunWith(SpringRunner.class)
@SpringBootTest({"myCustomArgs.customArg1=testValue"})
public class CityApplicationTests {
@Test
public void contextLoads() {
}
}
명령줄 앱을 실행할 때는 사용자 지정 매개 변수를 추가하면 됩니다.
--myCustomArgs.customArg1=testValue
저는 SpringBoot를 그 방정식에서 제외할 것입니다.
테스트만 하면 됩니다.run
방법, 스프링 부트를 거치지 않고, 당신의 목표는 스프링 부트를 테스트하는 것이 아니기 때문에, 그렇지 않나요? 제 생각에, 이 테스트의 목적은 회귀를 위한 것이고, 당신의 애플리케이션이 항상 그것을 던지도록 보장합니다.IllegalArgumentException
Arg가 제공되지 않을 때?이전의 양호한 장치 테스트는 여전히 단일 방법을 테스트하는 데 사용됩니다.
@RunWith(MockitoJUnitRunner.class)
public class ApplicationTest {
@InjectMocks
private Application app = new Application();
@Mock
private Reader reader;
@Mock
private Writer writer;
@Test(expected = IllegalArgumentException.class)
public void testNoArgs() throws Exception {
app.run();
}
@Test
public void testWithArgs() throws Exception {
List list = new ArrayList();
list.add("test");
Mockito.when(reader.get(Mockito.anyString())).thenReturn(list);
app.run("myarg");
Mockito.verify(reader, VerificationModeFactory.times(1)).get(Mockito.anyString());
Mockito.verify(writer, VerificationModeFactory.times(1)).write(list);
}
}
나는 Mockito를 사용하여 독자와 작가를 위한 모의실험을 했습니다.
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
스프링은 다음과 같습니다.ApplicationArguments
.사용하다getSourceArgs()
명령줄 인수를 검색합니다.
public CityApplicationService(ApplicationArguments args, Writer writer){
public void writeFirstArg(){
writer.write(args.getSourceArgs()[0]);
}
}
테스트에서 응용 프로그램 인수를 모의실험합니다.
@RunWith(SpringRunner.class)
@SpringBootTest
public class CityApplicationTests {
@MockBean
private ApplicationArguments args;
@Test
public void contextLoads() {
// given
Mockito.when(args.getSourceArgs()).thenReturn(new String[]{"Berlin"});
// when
ctx.getBean(CityApplicationService.class).writeFirstArg();
// then
Mockito.verify(writer).write(Matchers.eq("Berlin"));
}
}
Maciej Marczuk이 제안한 것처럼, 저도 Springs를 사용하는 것을 선호합니다.Environment
명령줄 인수 대신 속성을 입력합니다. 구문을 할 수 에는 스프링 구문을 할 수 없습니다.--argument=value
당신은 자신의 것을 쓸 수 있습니다.PropertySource
으로 채운 " " " " " 에 합니다.ConfigurableEnvironment
그러면 모든 클래스에서 스프링 환경 속성만 사용하면 됩니다.
예.
public class ArgsPropertySource extends PropertySource<Map<String, String>> {
ArgsPropertySource(List<CmdArg> cmdArgs, List<String> arguments) {
super("My special commandline arguments", new HashMap<>());
// CmdArgs maps the property name to the argument value.
cmdArgs.forEach(cmd -> cmd.mapArgument(source, arguments));
}
@Override
public Object getProperty(String name) {
return source.get(name);
}
}
public class SetupArgs {
SetupArgs(ConfigurableEnvironment env, ArgsMapping mapping) {
// In real world, this code would be in an own method.
ArgsPropertySource = new ArgsPropertySource(mapping.get(), args.getSourceArgs());
environment
.getPropertySources()
.addFirst(propertySource);
}
}
BTW:
저는 답변을 제시하기에 충분한 평판 포인트가 없기 때문에 여전히 여기에 열심히 배운 교훈을 남기고 싶습니다.
그CommandlineRunner
그렇게 좋은 대안은 아닙니다.이왕이면run()
메서드는 항상 스프링 컨텍스트 생성 직후에 실행됩니다.심지어 시험 수업에서도.테스트가 시작되기 전에 실행됩니다.
필요한 것은 다음과 같습니다.
@SpringBootTest(args = "test")
class YourApplicationTests {
@Test
public void contextLoads() {
}
}
이 답변에서 언급한 것처럼 스프링 부트는 현재 사용하는 DefaultApplicationArguments를 가로채거나 대체할 수 있는 방법을 제공하지 않습니다.이 문제를 해결하기 위해 사용한 자연스러운 부팅 방법은 러너 로직을 향상시키고 몇 가지 자동 배선된 속성을 사용하는 것이었습니다.
먼저 속성 구성 요소를 만들었습니다.
@ConfigurationProperties("app") @Component @Data
public class AppProperties {
boolean failOnEmptyFileList = true;
boolean exitWhenFinished = true;
}
... 속성 구성 요소를 러너에 자동 배선했습니다.
@Service
public class Loader implements ApplicationRunner {
private AppProperties properties;
@Autowired
public Loader(AppProperties properties) {
this.properties = properties;
}
...
...에서.그리고, 그 안에서.run
해당 된 경우에만 은 " assert"("assert")입니다.true
일반 애플리케이션 사용의 경우:
@Override
public void run(ApplicationArguments args) throws Exception {
if (properties.isFailOnEmptyFileList()) {
Assert.notEmpty(args.getNonOptionArgs(), "Pass at least one filename on the command line");
}
// ...do some loading of files and such
if (properties.isExitWhenFinished()) {
System.exit(0);
}
}
이를 통해 유닛 테스트에 적합한 방식으로 실행할 수 있도록 속성을 조정할 수 있습니다.
@RunWith(SpringRunner.class)
@SpringBootTest(properties = {
"app.failOnEmptyFileList=false",
"app.exitWhenFinished=false"
})
public class InconsistentJsonApplicationTests {
@Test
public void contextLoads() {
}
}
나는 필요했습니다.exitWhenFinished
내 특정 주자가 보통 전화를 한 이후로.System.exit(0)
그런 식으로 빠져나오면 장치 테스트는 반자동 상태가 됩니다.
6월 5일에는 @SpringBootTest(args = "20210831")에 있는 args parm을 사용하여 Commandline 인수를 전달할 수 있습니다.
@ExtendWith(SpringExtension.class)
@SpringBootTest(args = "20210831")
@TestPropertySource("/application-test.properties")
@ContextConfiguration(classes = {Test.class, TestConfig.class})
public class AppleTest {
언급URL : https://stackoverflow.com/questions/39144136/using-junit-test-to-pass-command-line-argument-to-spring-boot-application
'bestsource' 카테고리의 다른 글
Git 사용자를 위한 Perforce? (0) | 2023.07.08 |
---|---|
유형 오류: JSX 요소 유형 '{} | null | defined'는 JSX 요소에 대한 생성자 함수가 아닙니다. (0) | 2023.07.08 |
가져오기 오류: 이름이 암호화된 모듈이 없습니다.사이퍼 (0) | 2023.07.03 |
윈도우즈 7에 ROracle 패키지를 설치하는 방법은 무엇입니까? (0) | 2023.07.03 |
예외: BSON 유형 EOO에서 날짜로 변환할 수 없습니다. (0) | 2023.07.03 |