在测试期间排除Spring Boot中的ApplicationListener @Component

时间:2017-06-22 14:37:13

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

我正在努力让我的测试单元启动并运行,我遇到了一个奇怪的问题。我的应用程序使用注释为@Component的ApplicationListener类来在启动期间执行操作。

在测试期间,我已经模拟了包含逻辑的服务,但我发现即使Mockito在指令在控制器范围内运行良好时,也没有为此ApplicationListener类初始化bean:而不是返回我定义的内容在测试单元中,它返回false或null - 取决于服务中每个方法返回的数据类型。

由于我没有找到任何方法从ApplicationListener类的测试单元初始化模拟服务,我决定将其排除。为此,我尝试了不同的方法,最常用的方法是创建测试应用程序上下文并更改其配置。不幸的是,我所看到的一切都没有用 - 所以我在这里寻求帮助。如果可能的话,我宁愿不接触ApplicationListener类并在测试代码中进行所有相关的编码。

我对两种可能的解决方案中的任何一种感兴趣,如果可以的话:

1.-在ApplicationListener执行期间获取模拟行为,但我已经读过某些地方无法完成此操作

2.-以某种方式从测试单元中排除@Component。

TestUnit.Java

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class TestConfigurationService { 
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @MockBean
    private MockService mockService;

    private void initMockBean () throws Exception {
        when(mockService.isDoingSomething()).thenReturn(true);
    }

    @Before
    public void setup() throws Exception {
        // Spring mock context application setup
        this.mockMvc = webAppContextSetup(webApplicationContext).build();

        // Initialize ConsulService mock bean
        initMockBean ();
    }
}

TestApplication.java

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages="my.base.package", excludeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = StartupConfiguration.class))
public class TestApplication {
    public static void main(String[] args) {    
        SpringApplication.run(TestApplication.class, args);
    }
}

除了代码中显示的内容外,我还在文件TestApplication.java中尝试了这个注释:

@SpringBootApplication(exclude={StartupConfiguration.class})

StartupConfiguration.java

@Component
public class StartupConfiguration implements ApplicationListener<ContextRefreshedEvent> {   
    @Autowired
    private ConfigurationService configurationService;

    @Override
    public void onApplicationEvent(final ContextRefreshedEvent event) {     
        try {
            configurationService.updateConfiguration();
        } catch (Exception e) {
            throw new RuntimeException ("Error", e);
        }
    }
}

ConfigurationService.java

public interface ConfigurationService {
    public void updateConfiguration () throws Exception;
}

ConfigurationServiceImpl.java

@Service
@Transactional
public class ConfigurationServiceImpl implements ConfigurationService {     
    @Autowired
    private MService mockService;

    @Override
    public void updateConfiguration() throws Exception {    
        if (mockService.isDoingSomething()==false)
            throw new Exception ("Something went wrong");
    }
}

版本

Spring Boot 1.5.4.RELEASE,

Java 1.8

2 个答案:

答案 0 :(得分:0)

您可以创建相同类型的模拟bean,并使用@Primary注释标记它以替换真实bean。您可以通过测试此类配置来实现此目的:

@Configuration
@Import(TestApplication.class)
public class TestConfiguration {
    @Bean
    @Primary
    public ConfigurationService configurationService() {
        return Mockito.mock(ConfigurationService.class);
    }
}

然后在测试中得到这个模拟:

...
public class TestConfigurationService { 
    ...
    @Autowired
    ConfigurationService configurationService;

    @Before
    public void setUp() {
        when(mockService.isDoingSomething()).thenReturn(true);
    }
}

答案 1 :(得分:0)

谢谢,araxn1d。你的回答给了我解决这个问题的线索。

我在TestUnit.java中模拟了StartupConfiguration类:

@MockBean
private StartupConfiguration startupConfiguration;

虽然在这种情况下我很幸运:应用程序听众没有返回方法,所以他们在测试配置时不需要。如果我要求某些方法返回例如true或值,则此方法将不适用。

但至少对于应用程序监听器来说,这已经足够了。