Загрузка контекста приложения через аннотацию в бенчмарке

#java #spring #unit-testing #spring-mvc #annotations

#java #весна #модульное тестирование #spring-mvc #аннотации

Вопрос:

Предположим, я хочу написать benchmark для класса, который может быть autowired , таким образом, мне нужно загрузить application context .

Мой тест имеет аннотацию @org.openjdk.jmh.annotations.State(Scope.Benchmark) и основной метод

 public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(MyBenchmark.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
  

И, конечно, у меня есть несколько таких тестов:

 @Benchmark
public void countAllObjects() {
    Assert.assertEquals(OBJECT_COUNT, myAutowiredService.count());
}
  

Теперь вопрос в том, как мне внедрить myAutowiredService ?

Возможное решение

Загрузите контекст вручную в @Setup методе.

 ApplicationContext context = new ClassPathXmlApplicationContext("META-INF/application-context.xml");
context.getAutowireCapableBeanFactory().autowireBean(this);
  

Но мне не нравится это решение. Я бы предпочел, чтобы в моем тесте была только аннотация

 @ContextConfiguration(locations = { "classpath:META-INF/application-context.xml" })
  

а затем я просто вводю свой компонент, например

 @Autowired
private MyAutowiredService myAutowiredService;
  

но это не работает. Я полагаю, причина в том, что у меня нет аннотации, что мой тест должен выполняться с Spring:

 @RunWith(SpringJUnit4ClassRunner.class)
  

Однако нет смысла делать это, потому что у меня также нет никаких @Test аннотированных методов, поэтому я получу No runnable methods исключение.

Могу ли я добиться загрузки контекста через аннотации в этом случае?

Комментарии:

1. вы когда-нибудь находили решение?

Ответ №1:

Я нахожу код из spring-cloud-sleuth, он работает для меня

 @State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
public class DemoApplicationTests {

    volatile DemoApplication app;

    volatile ConfigurableApplicationContext context;

    private VideoService videoService;

    @Test
    public void contextLoads() throws RunnerException {
        Options opt = new OptionsBuilder()
            .include(DemoApplicationTests.class.getSimpleName())
            .forks(1)
            .build();
        new Runner(opt).run();
    }

    @Setup
    public void setup() {
        this.context = new SpringApplication(DemoApplication.class).run();
        Object o = this.context.getBean(VideoService.class);
        videoService = (VideoService)o;
    }

    @TearDown
    public void tearDown(){
        this.context.close();
    }

    @Benchmark
    public String benchmark(){
        return videoService.find("z");
    }
  

Ответ №2:

 @State(Scope.Benchmark)
public static class SpringState {

    AnnotationConfigApplicationContext context;

    @Setup(Level.Trial)
    public void setup() {
        context = new AnnotationConfigApplicationContext();
        context.register(CLASSNAME.class);
        context.register(ANOTHER_CLASSNAME_TO_BE_LOADED.class);
        context.refresh();
    }

    @TearDown(Level.Trial)
    public void tearDown() {
        context.close();
    }
}
  

Ответ №3:

Я бы выбрал getAutowireCapableBeanFactory().autowire() решение, которое вы уже набросали.

Должен быть некоторый шаблонный код, который загружает контекст приложения и запускает автозапуск. Если вы предпочитаете указывать конфигурацию своего приложения с аннотациями, метод установки может выглядеть примерно так:

 AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(MyBenchmarkWithConfig.class);
context.refresh();
  

Комментарии:

1. На данный момент у меня все еще есть конфигурация на основе xml, но я предполагаю, что однажды я перейду на версию на основе аннотаций. Итак, основываясь на вашем ответе, кажется, что это невозможно сделать с помощью аннотаций, это правильно?

2. Я не тестировал это, но подход AnnotationConfigWebApplicationContext должен работать, если вы аннотируете свой класс MyBenchmark с помощью @ContextConfiguration, который указывает на XML-файл.