简体   繁体   English

如何在@SpringBootTest 中传递程序参数?

[英]How do you pass program arguments in a @SpringBootTest?

I'm building a spring boot application.我正在构建一个 spring boot 应用程序。 I want to run it like this:我想像这样运行它:

 java -jar myjar.jar inputFile outputFile

How do I write a @SpringBootTest for this?我如何为此编写@SpringBootTest I imagine that using @SpringBootTest would make Spring fail during startup because some of my code would say, "you need to provide an inputFile and outputFile".我想象使用@SpringBootTest会使 Spring 在启动期间失败,因为我的一些代码会说,“你需要提供一个 inputFile 和 outputFile”。 Is there a way to pass program arguments when using a @SpringBootTest ?使用@SpringBootTest时有没有办法传递程序参数?

I'm inferring from this answer that I may have to use a SpringApplicationBuilder to do this.我从这个答案推断我可能必须使用 SpringApplicationBuilder 来执行此操作。

I thought I had the answer but I was wrong.以为我有答案,但我错了。 This incorrect information may still be useful to some:这个不正确的信息可能对某些人仍然有用:


( This information is wrong. I think that some arguments can't be referred to in code as properties, but not all. I still don't know how to get the application arguments in a @SpringBootTest ) I was confused because I didn't understand the terminology. 这个信息是错误的。我认为有些参数不能在代码中作为属性引用,但不是全部。我仍然不知道如何在@SpringBootTest中获取应用程序参数)我很困惑,因为我没有不懂术语。 The annotation has a parameter for "properties".注释有一个“属性”参数。 I thought it was to point it at a property file, but the documentation says :我以为是将它指向一个属性文件,但文档说

Properties in form key=value that should be added to the Spring Environment before the test runs.在测试运行之前应该添加到 Spring 环境中的 key=value 形式的属性。

The other piece of the terminology puzzle is that what I called "program arguments" the Spring docs refer to as "properties".另一个术语难题是我称之为“程序参数”的东西,Spring 文档将其称为“属性”。

This is some additional relevant documentation: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-application-arguments这是一些额外的相关文档: https ://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-application-arguments


This is a workaround (not an answer).这是一种解决方法(不是答案)。 You can do something like this:你可以这样做:

private SpringApplicationBuilder subject;

@Before
public void setUp() throws Exception {
    subject = new SpringApplicationBuilder(Application.class);
}

@Test
public void requiresInputAndOutput() throws Exception {

    thrown.expect(IllegalStateException.class);
    subject.run();
}

@Test
public void happyPathHasNoErrors() throws Exception {

    subject.run(EXISTING_INPUT_FILE, "does_not_exist");
}

I don't like this very much.我不太喜欢这个。 It prevents me from using @Autowired elsewhere in my test.它阻止我在测试的其他地方使用@Autowired

if your program arguments is如果你的程序参数是

--arg1=val1

before springboot version 2.2.0 you can use在 springboot 版本 2.2.0 之前你可以使用

@SpringBootTest({"arg1=val1"})

after springboot 2.2.0 you can use在 springboot 2.2.0 之后你可以使用

@SpringBootTest(args={"--arg1=val1"})

I had the same issue.我遇到过同样的问题。 Out of the box, the SpringBootContextLoader (used by default with @SpringBootTest ) always runs your app without any arguments .开箱即用的SpringBootContextLoader (默认情况下与@SpringBootTest一起使用) 始终在不带任何参数的情况下运行您的应用程序 However, you can provide your own bootstrapper, which can then in turn provide your own SpringApplication that gets called to run your test.但是,您可以提供自己的引导程序,然后它又可以提供您自己的SpringApplication ,调用它来运行您的测试。 From there, you can override the run(String... args) method to provide whatever arguments you want.从那里,您可以覆盖run(String... args)方法以提供您想要的任何参数。

For example, given a simple application:例如,给定一个简单的应用程序:

@SpringBootApplication
public class Main {
    public static void main(final String[] args) {
        new SpringApplicationBuilder(Main.class).run(args);
    }

    @Bean
    public ApplicationRunner app() {
        return args -> System.out.println(args.getOptionNames());
    }
}

You can inject test arguments with:您可以使用以下方式注入测试参数:

@ContextConfiguration(classes = Main.class)
@ExtendWith(SpringExtension.class)
@BootstrapWith(RestartAppsTest.Bootstrapper.class)
class RestartAppsTest {

    static class Bootstrapper extends SpringBootTestContextBootstrapper {
        static class ArgumentSupplyingContextLoader extends SpringBootContextLoader {
            @Override
            protected SpringApplication getSpringApplication() {
                return new SpringApplication() {
                    @Override
                    public ConfigurableApplicationContext run(String... args) {
                        return super.run("--restart");
                    }
                };
            }
        }

        @Override
        protected Class<? extends ContextLoader> getDefaultContextLoaderClass(Class<?> testClass) {
            return ArgumentSupplyingContextLoader.class;
        }
    }

    @Test
    void testRestart() {
        // 
    }
}

It's obviously a bit verbose, but it works.这显然有点冗长,但它确实有效。 You could clean it up and make a nicer/reusable bootstrapper that looked for your own annotation (or possibly reuse JUnit Jupiter's @Arguments ) that declared what arguments to supply (instead of hardcoding them).您可以清理它并制作一个更好/可重用的引导程序来寻找您自己的注释(或者可能重用 JUnit Jupiter 的@Arguments )声明要提供的参数(而不是对它们进行硬编码)。

You can use @SpringBootTest(classes=Application.class, args ={inputFile, outputFile}) if your app's main method looks a little different like如果您的应用程序的主要方法看起来有点不同,您可以使用@SpringBootTest(classes=Application.class, args ={inputFile, outputFile})

public static void main(String[] args){ 
     SpringApplication.run(Application.class, args);
}

For me working example is对我来说工作的例子是

@SpringBootTest(args ={"--env", "test"})
class QuickFixServerAppTest {

    @Test
    void loadContextTest() {
    }
}

is the same as passing the与通过相同

--env test

argument when starting Spring启动Spring时的争论

Normally you're writing tests for your services;通常,您正在为您的服务编写测试; not the boot strapper.不是引导带。 Spring Boot will pass command line parameters to your classes - perhaps using the @Value annotation, which in turn will be parameters to your service. Spring Boot 会将命令行参数传递给您的类 - 可能使用 @Value 注释,这又将成为您服务的参数。 Consider testing your services using the SpringRunner.考虑使用 SpringRunner 测试您的服务。 Here's an example from my code base.这是我的代码库中的一个示例。

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {
    Neo4jConfigTest.class,
    FdTemplate.class,
    FdServerIo.class,
    MapBasedStorageProxy.class})
@ActiveProfiles({"dev", "fd-auth-test", "fd-client"})
public class TestEntityLinks  {

@Autowired
private ContentModelService contentModelService;

@Autowired
private BatchService batchService;

@Test
public void doSomething () { ... }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM