Spring Boot - 单元测试ApplicationReadyEvent业务逻辑

vto*_*osh 3 spring unit-testing spring-boot

我有一个简单的服务,我user用默认用户预填充数据库表。该服务如下所示:

@Service
public class BootstrapService
{
    @Autowired
    UserRepository userRepository;

    public void bootstrap()
    {
        User user = new User("admin", "password");
        userRepository.save(user);
    }
}
Run Code Online (Sandbox Code Playgroud)

我在应用程序启动时使用以下命令调用此服务ApplicationListener

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent>
{
    @Autowired
    private BootstrapService bootstrapService;

    @Override
    public void onApplicationEvent(final ApplicationReadyEvent event)
    {
        bootstrapService.bootstrap();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想编写一个单元测试来BootstrapService检查用户是否确实被添加,如下所示:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = MyApplication.class)
@Transactional
public class BootstrapServiceTests
{
    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BootstrapService bootstrapService;

    @Test
    public void testBootstrap()
    {
        bootstrapService.bootstrap();

        assertEquals(1, userRepository.count());
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,发生的情况是该bootstrapService.bootstrap()函数被调用两次 - 一次由ApplicationListener测试本身调用,一次由测试本身调用,导致两个用户被添加到数据库中。

如何防止ApplicationListener#ApplicationReadyEvent在运行测试时触发?

pat*_*s91 5

正如评论中提到的,您可以尝试模拟侦听器(但我不确定它在这种情况下是否有效)。我能想到的其他方法(这肯定有效)是使用 Spring 配置文件,将 ApplicationStartup 排除在测试配置文件中运行,如下所示:

@Component
@Profile("!test")
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent>
Run Code Online (Sandbox Code Playgroud)

然后,当您运行测试时,只需使用环境切换:--spring.profiles.active=test

缺点是 ApplicationStartup 将被排除在使用“test”配置文件的每次测试运行之外。