简体   繁体   中英

How do you pass program arguments in a @SpringBootTest?

I'm building a spring boot application. I want to run it like this:

 java -jar myjar.jar inputFile outputFile

How do I write a @SpringBootTest for this? 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". Is there a way to pass program arguments when using a @SpringBootTest ?

I'm inferring from this answer that I may have to use a SpringApplicationBuilder to do this.

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. 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.

The other piece of the terminology puzzle is that what I called "program arguments" the Spring docs refer to as "properties".

This is some additional relevant documentation: 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.

if your program arguments is

--arg1=val1

before springboot version 2.2.0 you can use

@SpringBootTest({"arg1=val1"})

after springboot 2.2.0 you can use

@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 . However, you can provide your own bootstrapper, which can then in turn provide your own SpringApplication that gets called to run your test. From there, you can override the run(String... args) method to provide whatever arguments you want.

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).

You can use @SpringBootTest(classes=Application.class, args ={inputFile, outputFile}) if your app's main method looks a little different like

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

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. Consider testing your services using the 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 () { ... }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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