오늘은 아직 릴리즈 되지는 않았지만 그래도 큰 변화를 없을 것 같아 이렇게 포스팅을 한다. 그 전에 올해 하반기에 자바진영에 많은 변화가 있을 것으로 예상된다. 그중에 이미 릴리즈 된 Junit5 가 첫 번째 변화이고 두 번째로 자바9(9월 21일), spring5 (9월 28일) spring boot 2.0(11월 20일) 등이 릴리즈 될 예정이다. 하지만 예정은 예정일뿐.. 언제 바뀔지는 모른다. spring5 와 spring boot 2 는 모두 자바 8 이상에서만 작동한다. 그러니 이제는 자바8을 꼭 쓰도록 하자. 그건 그렇고 java EE가 이제는 이클립스재단으로 간다는.. 좋은 소식(?)

아무튼 오늘은 Spring boot 2 에 추가된 ApplicationContextRunner에 대해서 살펴보도록 하자. ApplicationContextRunner의 용도는 테스트로 사용하는 클래스인데 특정한 설정 정보를 불러와서 테스트를 하기에 적합한 클래스이다. 또 한 좀 더 모던한 스타일을 제공하므로 java8의 문법(람다 표현식) 을 사용할 수 도 있고 AssertJ 스타일의 assertions을 제공해 주고 있다. 그나저나 Spring boot가 이제는 AssertJ를 밀고 있는 듯 하다.

ApplicationContextRunner 말고도 WebApplicationContextRunner, ReactiveWebApplicationContextRunner 등이 존재하나 거의 비슷하지 않을까 싶다. 예제를 살펴보면서 해보도록 하자.

public class ApplicationContextRunnerTest {

  private final ApplicationContextRunner contextRunner = new ApplicationContextRunner();

  @Test
  public void fooTest() {
    contextRunner.withUserConfiguration(FooConfiguration.class)
        .run(context -> {
          assertThat(context).hasBean("foo");
          assertThat(context).getBean("foo").isEqualTo("foo");
        });
  }

  @Configuration
  protected static class FooConfiguration {

    @Bean
    public String foo() {
      return "foo";
    }
  }
}

클래스 레벨에 ApplicationContextRunner을 필드로 선언하면 된다. 기본적으로는 AnnotationConfigApplicationContext를 컨테이너로 사용한다. 만약 다른 컨테이너를 사용하고 싶다면 아래와 같이 변경하면 된다.

private final ApplicationContextRunner contextRunner = new ApplicationContextRunner(GenericWebApplicationContext::new);

어떠한 특정한 설정을 추가적으로 하고 싶다면 withUserConfiguration() 메서드를 사용해서 configuration 정보를 등록 시킬 수 있다. withUserConfiguration() 메서드 말고 withConfiguration() 메서드로 존재하는데 하는 역할을 동일해 보인다. 실제 Spring boot가 사용하는 패턴을 보면 withConfiguration() 메서드에는 테스트 클래스 전체의 기본설정을 하고 withUserConfiguration() 메서드는 해당하는 테스트에만 설정이 필요한 경우에만 사용하는 것으로 보인긴 하나 굳이 뭐 그럴 필요는 없어 보인다.

예를 들면 다음과 같다.

public class CacheApplicationTests {

  private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
      .withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class));

  @Test
  public void simpleCacheTest() {
    contextRunner.withUserConfiguration(DefaultConfiguration.class)
        .run(context -> {
          assertThat(context).hasBean("cacheManager");
          assertThat(context).getBean(CacheManager.class).isInstanceOf(ConcurrentMapCacheManager.class);
        });
  }

  @Configuration
  @EnableCaching
  static class DefaultConfiguration {

  }
}

이렇게 테스트 클래스의 기본 설정인 CacheAutoConfiguration을 기본적으로 등록하고 나머지 각각의 테스트에는 그에 맞게 설정 정보를 작성하면 된다. 뭐가 좀 다르긴 하나? 코드로 봐서는 다른 걸 못느끼겠지만..

ApplicationContextRunner에 프로퍼티도 등록하여 테스트 할 수 있는데 withPropertyValues() 메서드를 사용해서 pairs 정보를 String으로 넣으면 된다.

public class CacheApplicationTests {

  private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
      .withConfiguration(AutoConfigurations.of(CacheAutoConfiguration.class));

  @Test
  public void simpleCacheTest() {
    contextRunner.withUserConfiguration(DefaultConfiguration.class)
        .withPropertyValues("spring.cache.type=simple")
        .run(context -> {
          assertThat(context).hasBean("cacheManager");
          assertThat(context).getBean(CacheManager.class).isInstanceOf(ConcurrentMapCacheManager.class);
        });
  }

  @Test
  public void caffeineCacheTest() {
    contextRunner.withUserConfiguration(DefaultConfiguration.class)
        .withPropertyValues("spring.cache.type=caffeine")
        .run(context -> {
          assertThat(context).hasBean("cacheManager");
          assertThat(context).getBean(CacheManager.class).isInstanceOf(CaffeineCacheManager.class);
        });

  }

  @Configuration
  @EnableCaching
  static class DefaultConfiguration {

  }
}

위와 같이 withPropertyValues() 메서드를 사용해서 cache.type을 caffeine으로 등록하게 하였다. 이외에도 withParent(), withClassLoader(), withSystemProperties() 가 존재한다. 아직은 자주 사용될 만한 메서드는 아닌 것 같아서 생략한다. 주로 사용될 메서드는 withUserConfiguration(), withConfiguration(), withPropertyValues() 메서드이기 때문에 이 세가지만 봐도 아직은 괜찮을 것 같다. (물론 필자 생각)

Spring boot는 test에도 관심을 많이 가져준다. boot 1.4 부터 아주 다양하고 사용하기 쉽게 테스트를 도와주는 클래스들이 많으니 1.4부터 차근차근 보는 것을 추천한다. 조만간 나올 spring5 에서 reactive stream 을 지원하니 필자도 공부좀 해놔야 겠다. 당장은 운영에서는 사용할 일이 없더라도 사용할 일이 생긴다면 별 무리 없이 사용하기 위해 봐야겠다. 예전부터 관심은 있었지만 공부를 계속 미루다보니 나올때 공부를 시작하는거 아닐까 싶다.

오늘은 이렇게 Spring boot 2.0에 작은 변화를 살펴봤다. 아주 많은 변화가 있을 예정이지만 언제 다 살펴보지?