spring动态@bean注册springapplicationbuilder测试失败

ev7lccsx  于 2021-07-07  发布在  Java
关注(0)|答案(1)|浏览(316)

尝试通过springapplicationbuilder类动态注册bean,它在运行应用程序时工作,但是当尝试执行测试并验证bean是否在上下文中定义时,它们对动态bean失败。我觉得我必须为测试使用另一个“神奇的”注解,以便正确地加载动态bean。
这是使用的代码,如果您运行测试,您将看到这两种情况都将失败。barservice也会失败,因为fooservice是通过builder动态注册的,但是如果您删除依赖关系,它将通过barservice测试。
springapp.java版本

class FooService {

}

@Component
class BarService {
  private final FooService fooService;

  BarService(FooService fooService) {
    this.fooService = fooService;
  }
}

@SpringBootApplication
public class SpringApp {

  public static void main(String[] args) {
    new SpringApplicationBuilder()
      .sources(SpringApp.class)
      .initializers((ApplicationContextInitializer<GenericApplicationContext>) context -> {
        context.registerBean(FooService.class);
      })
      .run(args);
  }
}

springapptest.java文件

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringApp.class)
public class SpringAppTest {
  @Autowired
  ApplicationContext context;

  @Test
  public void barService() {
    Assert.assertNotNull("The barService should not be null", context.getBean(BarService.class));
  }

  @Test
  public void contextLoads() {
    Assert.assertNotNull("The fooService should not be null", context.getBean(FooService.class));
  }
}
xienkqul

xienkqul1#

第一个解决方案

这里的主要错误是测试没有main方法所具有的初始化逻辑。解决方法是从 initializers 方法

class MyInitializer implements ApplicationContextInitializer<GenericApplicationContext> {
  @Override
  public void initialize(GenericApplicationContext context) {
    System.out.println("Called initialize");
    context.registerBean(FooService.class);
  }
}

并在主屏幕上使用它

public static void main(String[] args) {
  new SpringApplicationBuilder()
    .sources(SpringApp.class)
    .initializers(new MyInitializer())
    .run(args);
}

然后通过@conextconfiguration在测试文件中使用myinitializer

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = SpringApp.class, initializers = MyInitializer.class)
public class SpringAppTest {
    // ...
}

第二个(更好的)解决方案

现在,这可能很麻烦,因为我们需要在每个测试中引用这个初始值设定项,但是有一个更好的解决方案。我们可以创建一个特定的spring文件 resources/META-INF/spring.factories 在里面放一个对初始值设定项的引用:

org.springframework.context.ApplicationContextInitializer=com.acme.orders.MyInitializer

之后,我们可以简化这两种主要方法

@SpringBootApplication
public class SpringApp {
  public static void main(String[] args) {
    SpringApplication.run(SpringApp.class, args);
  }
}

以及测试,这样他们就不必总是导入初始值设定项。

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringAppTest {
    // ...
}

现在,主运行进程和测试都可以访问所有bean。

相关问题