【问题标题】:Loading application context via annotation in benchmark通过基准中的注释加载应用程序上下文
【发布时间】:2023-03-08 06:16:02
【问题描述】:

假设我想为可以是autowired 的类写一个benchmark,因此我需要加载application context

我的测试有注解@org.openjdk.jmh.annotations.State(Scope.Benchmark)和main方法

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

然后我就像注入我的 bean 一样

@Autowired
private MyAutowiredService myAutowiredService;

但这不起作用。我认为原因是我有 no 注释,我的测试应该使用 Spring 运行:

@RunWith(SpringJUnit4ClassRunner.class)

但是这样做没有意义,因为我也没有任何 @Test 注释方法,因此我会得到 No runnable methods 异常。

这种情况下能否通过注解实现上下文加载?

【问题讨论】:

  • 您找到解决方案了吗?

标签: java spring unit-testing spring-mvc annotations


【解决方案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】:

    我会选择您已经草拟的getAutowireCapableBeanFactory().autowire() 解决方案。

    必须有一些样板代码来加载应用程序上下文并触发自动装配。如果您更喜欢使用注释指定您的应用程序配置,则 setup 方法可能如下所示:

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

    【讨论】:

    • 现在我仍然有基于 xml 的配置,但我想有一天我会转向基于注释的版本。那么,根据您的回答,似乎不可能通过注释来做到这一点,对吗?
    • 我没有对此进行测试,但是如果您使用指向 xml 文件的 @ContextConfiguration 注释您的 MyBenchmark 类,AnnotationConfigWebApplicationContext 方法应该可以工作。
    【解决方案3】:
    @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();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 2016-06-27
      相关资源
      最近更新 更多