Как использовать поля @Values ​​в @Rule в JUnit? - PullRequest
1 голос
/ 19 июня 2019

Как я могу использовать @Value вставленные пружиной свойства в определении junit @Rule?

Справочная информация. Я хочу создать тест junit со встроенным сервером sftp памяти, используя FakeSftpServerRule.

Проблема: @Rule выполняется до того, как поле @Value будет введено.

@Value("${ftp.port}")
private Integer port;

@Value("${ftp.user}")
private String user;

@Value("${ftp.pass}")
private String pass;

@Rule
public final FakeSftpServerRule sftpServer = new FakeSftpServerRule().setPort(port).addUser(user, pass);

1 Ответ

1 голос
/ 19 июня 2019

Одним из решений для решения вашей проблемы является инициализация контекста Spring и выполнение поиска свойств самостоятельно, как указано в моем первоначальном комментарии, и ссылается на образец , который иллюстрирует эту концепцию.

Проблема здесь заключается в том, что если вы не позаботитесь о том, чтобы в конечном итоге вы могли инициализировать контекст Spring дважды, один раз со статическим определением и один раз с обычной настройкой теста Spring.

К счастью, SpringСам по себе поставляется с AbstractJUnit4SpringContextTests классом поддержки, который позволяет вам повторно использовать уже загруженный Spring ApplicationContext.

Мы можем использовать эту функцию сейчас, чтобы инициализировать поддельный SFTP-сервер, но также разрешить внедрять bean-компоненты в тест-код без необходимости ручного поиска с помощью вызовов context.getBean(...).

Код ниже должен датьВы представляете, как это можно сделать:

@ContextConfiguration(classes = SpringTest.Config.class)
public class SpringTest extends AbstractJUnit4SpringContextTests {

  @Configuration
  @PropertySource("classpath:some.properties")
  static class Config {
    @Bean(name = "namedBean")
    String someBean() {
      return "Test";
    }

    @Bean
    UUID uuidGenerator() {
      return UUID.randomUUID();
    }
  }

  static ApplicationContext context;
  static int port;
  static String user;
  static String pass;

  static {
    context = new AnnotationConfigApplicationContext(SpringTest.Config.class);
    Environment env = context.getBean(Environment.class);
    String sPort = env.getProperty("port");
    port = Integer.parseInt(sPort);
    user = env.getProperty("user");
    pass = env.getProperty("pass");
  }

  @Autowired
  private UUID uuidGenerator;

  public SpringTest() {
    // reuse the already initialized Spring application context
    setApplicationContext(context);
  }

  @Rule
  public final FakeSftpServerRule sftpServer = 
          new FakeSftpServerRule().setPort(port).addUser(user, pass);

  @Test
  public void test() {
    String someBean = context.getBean("namedBean", String.class);
    System.out.println(someBean);

    System.out.println(uuidGenearator.toString());
    System.out.println(sftpServer.getPort());
  }
}

Вероятно, более элегантным способом было бы определить что-то подобное в конфигурации Spring:

@Configuration
@PropertySource("classpath:some.properties")
@EnableConfigurationProperties(SftpSettings.class)
static class Config {
  ...
}

, где SftpSettings - этопростой класс бина, такой как

@Validated
@Getter
@Setter
@ConfigurationProperties(prefix="sftp")
public class SftpSettings {
  @NotNull
  private int port;
  @NotNull
  private String user;
  @NotNull
  private String pass;
}

, а затем выполнить поиск по SftpSettings вместо Environment:

static {
  context = new AnnotationConfigApplicationContext(SpringTest.Config.class);
  SftpSettings settings = context.getBean(SftpSettings.class);
  port = settings.getPort();
  user = settings.getUser();
  pass = settings.getPass();
}

Таким образом Spring позаботится о поискезначения из файла свойств и при преобразовании этих значений в соответствующие форматы.

...