我有一个提供了结构的多模块Maven项目。
提供了我的配置文件,
@Getter
@Setter
@Component
public class EllaFilterConfigHolder {
private boolean internalBuyerFilterEnabled;
private boolean externalBuyerFilterEnabled;
private final Set<Integer> shopIdsToFilterSet = new HashSet<>();
}
EllaConfiguration
代码
@Configuration
@EnableAsync
@ComponentScan( "com.ratepay.iris.ella" )
public class EllaConfiguration {
public static final String ELLA_CONNECTOR_BEAN_NAME = "ellaConnector";
public static final String ELLA_THREAD_POOL_EXECUTOR_NAME = "ellaThreadPoolTaskExecutor";
public static final String URI_CONFIG_KEY = "ella.uri";
public static final String CONNECTION_TIMEOUT_CONFIG_KEY = "ella.connection_timeout";
public static final String READ_TIMEOUT_CONFIG_KEY = "ella.read_timeout";
public static final int DEFAULT_CONNECTION_TIMEOUT = 100;
public static final int DEFAULT_READ_TIMEOUT = 800;
@Bean( ELLA_CONNECTOR_BEAN_NAME )
public EntityServiceConnectable<EllaResponseDto> ellaConnector( final Environment env ) {
return ServiceConnectorBuilder.create( createConnectionConfiguration( env ) ).timeout( createTimeoutConfiguration( env ) ).build();
}
// ========================================================================
private PostConnectionConfiguration<EllaResponseDto> createConnectionConfiguration( final Environment env ) {
return new SimplePostConnectionConfiguration<>( env.getRequiredProperty( URI_CONFIG_KEY ), EllaResponseDto.class );
}
// ========================================================================
private SimpleTimeoutConfiguration createTimeoutConfiguration( final Environment env ) {
return new SimpleTimeoutConfiguration( env.getProperty( CONNECTION_TIMEOUT_CONFIG_KEY, Integer.class, DEFAULT_CONNECTION_TIMEOUT ),
env.getProperty( READ_TIMEOUT_CONFIG_KEY, Integer.class, DEFAULT_READ_TIMEOUT ) );
}
// ========================================================================
@Bean( ELLA_THREAD_POOL_EXECUTOR_NAME )
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.initialize();
return taskExecutor;
}
}
最后,EllaServiceConfiguration
代码
@Configuration
@Import( EllaConfiguration.class )
public class EllaServiceConfiguration {
private static final String SHOP_ID_STRING_SEPARATOR = ",";
public static final String ELLA_SHOP_ID_FILTER_ENABLED_KEY = "ella.shop.id.filter";
public static final String ELLA_INTERNAL_BUYER_FILTER_ENABLED_KEY = "ella.internal.buyer.filter";
public static final String ELLA_EXTERNAL_BUYER_FILTER_ENABLED_KEY = "ella.external.buyer.filter";
@Bean
public EllaFilterConfigHolder ellaFilterConfigHolder( final Environment environment ) {
final EllaFilterConfigHolder configHolder = new EllaFilterConfigHolder();
configHolder
.setInternalBuyerFilterEnabled( environment.getRequiredProperty( ELLA_INTERNAL_BUYER_FILTER_ENABLED_KEY, Boolean.class ) );
configHolder
.setExternalBuyerFilterEnabled( environment.getRequiredProperty( ELLA_EXTERNAL_BUYER_FILTER_ENABLED_KEY, Boolean.class ) );
Set<Integer> set = getShopIdsToFilterAsList( environment );
configHolder.getShopIdsToFilterSet().addAll( set );
return configHolder;
}
// ========================================================================
private Set<Integer> getShopIdsToFilterAsList( final Environment env ) {
String shopIdListStr = env.getRequiredProperty( ELLA_SHOP_ID_FILTER_ENABLED_KEY, String.class );
return new HashSet<>( Arrays.asList( shopIdListStr.split( SHOP_ID_STRING_SEPARATOR ) ).stream().map( Integer::parseInt )
.collect( Collectors.toSet() ) );
}
}
我有一个EllaService
类,我想为该类编写集成测试。
@Service
public class EllaService {
private static final Logger LOG = LoggerFactory.getLogger( EllaService.class );
@Autowired
@Qualifier( ELLA_CONNECTOR_BEAN_NAME )
private EntityServiceConnectable<EllaResponseDto> connector;
@Autowired
private EllaFilterConfigHolder configHolder;
@Autowired
private EllaServiceConfiguration config;
@Autowired
private Environment env;
/**
* Initialize the service.
*/
@PostConstruct
public void initialize() {
this.configHolder = config.ellaFilterConfigHolder( env );
}
// ========================================================================
/**
* Asynchronously call Ella. Determine if traffic is applicable for Ella and if yes forward to Ella.
*
* @param irisBo IrisBo object
*/
@Async( ELLA_THREAD_POOL_EXECUTOR_NAME )
public void invokeEllaAsync( final IrisBo irisBo ) {
if( isTrafficAllowed( irisBo ) ) {
callEllaService( irisBo );
}
}
// ========================================================================
/**
* Call ella service without processing service response.
*
* @param irisBo IrisBo object
*/
public void callEllaService( final IrisBo irisBo ) {
HttpHeaders ellaHeaders = createRequestHeaders( irisBo );
ServiceResponse<EllaResponseDto> response = connector.call( EllaDtoConverter.convertToRequest( irisBo ), ellaHeaders );
if( !response.isSuccess() ) {
LOG.error( "ERROR occured while calling ella async [ irisBo: {} - response: {}]", response, irisBo );
}
}
// ========================================================================
private boolean isTrafficAllowed( IrisBo irisBo ) {
if( configHolder.isExternalBuyerFilterEnabled() && irisBo.getBuyer().isExternalKnownCustomer() ) {
return false;
}
if( configHolder.isInternalBuyerFilterEnabled() && irisBo.getBuyer().isInternalKnownCustomer() ) {
return false;
}
return isShopNotConfigured( irisBo );
}
// ========================================================================
private boolean isShopNotConfigured( IrisBo irisBo ) {
return !configHolder.getShopIdsToFilterSet().contains( irisBo.getOrder().getShopId() );
}
// ========================================================================
private HttpHeaders createRequestHeaders( final IrisBo irisBo ) {
HttpHeaders ellaHeaders = new HttpHeaders();
ellaHeaders.add( ACCEPT, APPLICATION_JSON_UTF8_VALUE );
ellaHeaders.add( CONTENT_TYPE, APPLICATION_JSON_UTF8_VALUE );
RatepayHeaders.append( ellaHeaders, irisBo.getRequestInfo() );
return ellaHeaders;
}
}
我将集成测试的样板代码命名为EllaServiceIT
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration
@WebAppConfiguration
public class EllaServiceIT {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup( this.wac ).build();
}
@Test
public void testBusiness() {
System.out.println( "XYZ" );
}
}
我得到以下错误堆栈,
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.294 s <<< FAILURE! - in com.xyz.iris.ella.service.EllaServiceIT
[ERROR] initializationError(com.xyz.iris.ella.service.EllaServiceIT) Time elapsed: 0.007 s <<< ERROR!
java.lang.IllegalStateException: WebDelegatingSmartContextLoader was unable to detect defaults, and no ApplicationContextInitializers or ContextCustomizers were declared for context configuration attributes [[ContextConfigurationAttributes@400cff1a declaringClass = 'com.xyz.iris.ella.service.EllaServiceIT', classes = '{}', locations = '{}', inheritLocations = true, initializers = '{}', inheritInitializers = true, name = [null], contextLoaderClass = 'org.springframework.test.context.ContextLoader']]
更新
我对类进行了如下修改,
@RunWith( SpringJUnit4ClassRunner.class )
@ContextConfiguration(classes = { EllaServiceConfiguration.class })
@WebAppConfiguration(value = "com.ratepay.iris.ella.config")
public class EllaServiceIT {
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
@Before
public void setup() throws Exception {
this.mockMvc = MockMvcBuilders.webAppContextSetup( this.wac ).build();
}
@Test
public void testMl() {
System.out.println( "XYZ" );
}
}
我提供了一个经过修改的错误堆栈,
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.829 s <<< FAILURE! - in com.ratepay.iris.ella.service.EllaServiceIT
[ERROR] testMl(com.ratepay.iris.ella.service.EllaServiceIT) Time elapsed: 0.006 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'ellaService': Unsatisfied dependency expressed through field 'connector'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ellaConnector' defined in com.ratepay.iris.ella.config.EllaConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ratepay.commons.web.util.io.http.connector.EntityServiceConnectable]: Factory method 'ellaConnector' threw exception; nested exception is java.lang.IllegalStateException: Required key 'ella.uri' not found
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ellaConnector' defined in com.ratepay.iris.ella.config.EllaConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ratepay.commons.web.util.io.http.connector.EntityServiceConnectable]: Factory method 'ellaConnector' threw exception; nested exception is java.lang.IllegalStateException: Required key 'ella.uri' not found
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.ratepay.commons.web.util.io.http.connector.EntityServiceConnectable]: Factory method 'ellaConnector' threw exception; nested exception is java.lang.IllegalStateException: Required key 'ella.uri' not found
Caused by: java.lang.IllegalStateException: Required key 'ella.uri' not found
如何正确运行它?