Using junit test to pass command line argument to Spring Boot application

前端 未结 7 1544
抹茶落季
抹茶落季 2021-02-12 19:07

I have a very basic Spring Boot application, which is expecting an argument from command line, and without it doesn\'t work. Here is the code.

@SpringBootApplica         


        
7条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-02-12 19:56

    In your code autowire springs ApplicationArguments. Use getSourceArgs() to retrieve the commandline arguments.

    public CityApplicationService(ApplicationArguments args, Writer writer){        
        public void writeFirstArg(){
            writer.write(args.getSourceArgs()[0]);
        }
    }
    

    In your test mock the ApplicationArguments.

    @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"));
    
        }
    }
    

    Like Maciej Marczuk suggested, I also prefer to use Springs Environment properties instead of commandline arguments. But if you cannot use the springs syntax --argument=value you could write an own PropertySource, fill it with your commandline arguments syntax and add it to the ConfigurableEnvironment. Then all your classes only need to use springs Environment properties.

    E.g.

    public class ArgsPropertySource extends PropertySource> {
    
        ArgsPropertySource(List cmdArgs, List 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:

    Since I do not have enough reputation points to comment an answer, I would still like to leave a hard learned lesson here:

    The CommandlineRunner is not such a good alternative. Since its run() method alwyas gets executed right after the creation of the spring context. Even in a test-class. So it will run, before your Test started ...

提交回复
热议问题