Overriding Configuration properties with test container in Micronaut not working - java

Test container configuration
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Testcontainers
public abstract class TestContainerFixture {
#Container
protected static final GenericContainer mongoDBContainer;
protected static final Map<String, Object> properties;
static {
mongoDBContainer = new GenericContainer(DockerImageName.parse("mongo:4.0.10"))
.withExposedPorts(27017)
.withReuse(true);
mongoDBContainer.start();
properties = Map.of("mongodb.uri",
String.format("mongodb://%s:%s/FeteBird-Product",
mongoDBContainer.getContainerIpAddress(),
mongoDBContainer.getMappedPort(27017)));
}
protected static ApplicationContext applicationContext;
}
Application.yml
mongodb:
uri: "mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017}/FeteBird-Product"
database: "FeteBird-Product"
JUnit Testing
#MicronautTest(rebuildContext = true)
public class SubCategoryCreateTest extends TestContainerFixture {
#BeforeAll
public static void initUnitTest() {
applicationContext = ApplicationContext.run(properties, ConstantValues.TEST_ENVIRONMENT);
}
#Test
#DisplayName("Should create sub category with valid claim as Owner")
void shouldCreateSubCategoryWithValidClaimAsOwner() {
// Given
HttpResponse<CategoryModel> categoryrsp = this.httpRequestToCreateCategory();
assertEquals(categoryrsp.getStatus(), HttpStatus.CREATED);
// When
SubCategoryModel subCategoryModel = new SubCategoryModel(null, "Men swim sweat", "Men swim seat description");
HttpRequest request = HttpRequest.POST(String.format("%s/%s/%s", "category", categoryrsp.body().id(), "/sub-category"), subCategoryModel)
.bearerAuth(bearerAccessRefreshToken.getAccessToken());
HttpResponse<SubCategoryModel> rsp = client.toBlocking().exchange(request, SubCategoryModel.class);
var item = rsp.body();
// Then
assertEquals(rsp.getStatus(), HttpStatus.CREATED);
assertTrue(item.id() != null);
}
}
The configuration is not over-ridden in the service layer, Controller has the dependency on service layer
Update after implementing TestPropertyProvider works
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
#Testcontainers
public class TestContainerFixture implements TestPropertyProvider {
protected GenericContainer mongoDBContainer;
#Override
public Map<String, String> getProperties() {
mongoDBContainer = new GenericContainer(DockerImageName.parse("mongo:4.0.10"))
.withExposedPorts(27017)
.withReuse(true);
mongoDBContainer.start();
return Map.of("mongodb.uri",
String.format("mongodb://%s:%s/FeteBird-Product",
mongoDBContainer.getContainerIpAddress(),
mongoDBContainer.getMappedPort(27017)));
}
}
#MicronautTest
public class SubCategoryCreateTest extends TestPropertyProvider {
#Test
#DisplayName("Should create sub category with valid claim as Owner")
void shouldCreateSubCategoryWithValidClaimAsOwner() {
// Given
HttpResponse<CategoryModel> categoryrsp = this.httpRequestToCreateCategory();
assertEquals(categoryrsp.getStatus(), HttpStatus.CREATED);
// When
SubCategoryModel subCategoryModel = new SubCategoryModel(null, "Men swim sweat", "Men swim seat description");
HttpRequest request = HttpRequest.POST(String.format("%s/%s/%s", "category", categoryrsp.body().id(), "/sub-category"), subCategoryModel)
.bearerAuth(bearerAccessRefreshToken.getAccessToken());
HttpResponse<SubCategoryModel> rsp = client.toBlocking().exchange(request, SubCategoryModel.class);
var item = rsp.body();
// Then
assertEquals(rsp.getStatus(), HttpStatus.CREATED);
assertTrue(item.id() != null);
}
}

You need to implement TestPropertyProperty and set up your database URL in the getProperties method that it requires
See the guide here for an example

Related

how to create a Mock database and add data in mock db for integration testing using postgres db and java

I want to perform the Integration test for which I want to create a test DB and add some data.
how should I point to the test DB while doing an integration test?
Thanks for Help......
You can use testcontainers for achieving this. You can watch this video to get an idea about this and how to configure it in your spring boot application
For your spring integration test create a configuration like as shown below
AbstractIT.java
#Testcontainers
#SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT, properties = {"spring.main.allow-bean-definition-overriding=true"})
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // don't replace our DB with an in-memory one
#ContextConfiguration(initializers = AbstractIT.DockerPostgresDataSourceInitializer.class)
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public abstract class AbstractIT {
private static PostgreSQLContainer<?> postgresDBContainer = new PostgreSQLContainer<>("postgres:9.6")
.withUrlParam("TC_DAEMON", "true")
.withFileSystemBind("docker/db", "/docker-entrypoint-initdb.d", BindMode.READ_WRITE);
static {
postgresDBContainer.start();
}
public static class DockerPostgresDataSourceInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
Assertions.assertNotNull(applicationContext);
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(
applicationContext,
"spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true",
"spring.datasource.driver-class-name="+postgresDBContainer.getDriverClassName(),
"spring.datasource.url=" + postgresDBContainer.getJdbcUrl(),
"spring.datasource.username=" + postgresDBContainer.getUsername(),
"spring.datasource.password=" + postgresDBContainer.getPassword()
);
}
}
}
Now you can write your Integration test like as shown in the below sample example
UserControllerIT.java
class UserControllerIT extends AbstractIT {
#Autowired
private TestRestTemplate template;
#Autowired
private UserRepository userRepository;
#Test
#Order(1)
#DisplayName("Testing to get all the user details")
void getAllUsersTest() {
ResponseEntity<List<UserDTO>> response = this.template.exchange("/v1/users", GET, HttpEntity.EMPTY, new ParameterizedTypeReference<List<UserDTO>>() {
});
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody())
.isNotEmpty()
.hasSize(3)
.extracting(UserDTO::getEmail).containsAnyOf("user1#some.com");
}
#Test
#Order(2)
#DisplayName("Testing for saving user details")
void saveUsersTest() {
ResponseEntity<Void> response = this.template.postForEntity("/v1/users", new HttpEntity<>(buildUserRequest()), Void.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
long usersCount = userRepository.count();
assertThat(usersCount).isEqualTo(4);
}
#Test
#Order(3)
#DisplayName("Testing to deleting user details by id")
void deleteUsersTest() {
this.template.delete("/v1/users/{id}", singleParam("id", "21"));
boolean userExists = userRepository.existsById(21L);
assertThat(userExists).isFalse();
}
#Test
#Order(4)
#DisplayName("Testing to finding user details by id")
void findUserByIdTest() {
ResponseEntity<UserDTO> response = this.template.getForEntity("/v1/users/{id}", UserDTO.class, singleParam("id", "22"));
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody())
.extracting(UserDTO::getEmail, UserDTO::getFirstName, UserDTO::getLastName)
.containsExactly("user2#some.com", "John", "Duke");
}
private UserDTO buildUserRequest() {
return UserDTO.builder()
.email("user4#some.com")
.lastName("Maria")
.firstName("Fernandes")
.build();
}
private Map<String, String> singleParam(String key, String value) {
Map<String, String> params = new HashMap<>();
params.put(key, value);
return params;
}
}
You can see the full running application under this Github Repo - https://github.com/nidhishkrishnan/stackoverflow/tree/master/employee-testcontainer

How to test a component with websocket scope?

I'm trying to build a simple test of a simple component marked with websocket scope. The problem is that I get this error:
Scope 'websocket' is not active for the current thread;
Which makes sense, because I'm using a simulated WebSocket client to perform a login, and on the client side context of the Spring app the websocket session created by the client has no impact.
What is the proper way to test websocket scoped components?
Component class:
#Service
#Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class TrackerService {
private final ConcurrentMap<String, Collection<Geolocation>> vehicleBeingTracked = new ConcurrentHashMap<>();
public void startTracking(String plateSequence) {
vehiclesBeingTracked.put(plateSequence, new ArrayList<>());
}
public void stopTracking(String plateSequence) {
vehiclesBeingTracked.remove(plateSequence);
}
public void spotVehicle(String plateSequence, Geolocation geo) {
vehiclesBeingTracked.get(plateSequence).add(geo);
}
public boolean isBeingTracked(String plateSequence) {
return vehiclesBeingTracked.containsKey(plateSequence);
}
}
Controller class:
#Controller
#MessageMapping("/operational/tracker")
public class TrackerController {
#Autowired
private TrackerService trackerService;
#MessageMapping("/plate/{plateSequence}/track.start")
public void startTracking(#DestinationVariable("plateSequence") String plateSequence) {
trackerService.startTracking(plateSequence);
}
}
Test class:
#RunWith(SpringRunner.class)
#ContextConfiguration
#SpringBootTest(classes = UnifyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
#ActiveProfiles("test")
public class TrackerTest {
#Autowired
private TrackerService trackerService;
#Test
public void startTracking() {
TrackerClient client = new TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
boolean result = trackerService.isBeingTracked("ABC1234"); // Here is the error
Assert.assertTrue(result);
}
}
Try to spy the trackerService service with the following code inside test class:
#SpyBean
private TrackerService trackerService;
#Test
public void startTracking() {
TrackerClient client = new
TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
boolean result = Mockito.verify(trackerService).isBeingTracked("ABC1234");
Assert.assertTrue(result);
}
Updated answer:
#MockBean
private TrackerService trackerService;
#Test
public void startTracking() {
Mockito.doAnswer((Answer<Object>) invocationOnMock -> {
Object[] args = invocationOnMock.getArguments();
assertEquals("ABC1234", invocationOnMock.getArgument(0));
return null;
}).when(sessionTracker).sessionDestroyed(Mockito.any());
TrackerClient client = new
TrackerClient("ws://localhost:9050/operational/websocket", "admin", "admin");
client.connectAndWait();
client.send("/operational/tracker/plate/ABC1234/track.start");
TimeUnit.SECONDS.sleep(1);
}

Unable to call the function from the mocked component class

I have a junit test method as follows:
#SpringBootTest
public class StoreIdAssignmentServiceTest {
private static final Logger log = LoggerFactory
.getLogger(StoreIdAssignmentServiceTest.class);
#InjectMocks
private StoreIdAssignmentService storeIdAssignmentService;
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
#Mock
private DatabaseService databaseService;
#Test
public void rollUpFeed_Single_DealerAndStoreID_NoExisting() {
List<ScmsaPosTransRollup> scmsaPosTransRollupFeedList = new ArrayList<>();
ScmsaPosTransRollup posTransRollup = new ScmsaPosTransRollup();
posTransRollup.setJobLogId(8269726L);
posTransRollup.setDealerCode("3119255");
posTransRollup.setStoreId("9842");
posTransRollup.setTransactionDate(Timestamp
.valueOf("2018-03-01 13:00:00.00"));
posTransRollup.setQuantity(4);
posTransRollup.setRollupType("H");
scmsaPosTransRollupFeedList.add(posTransRollup);
Mockito.when(
databaseService.getUnProcessedRollUpFeedBasedonRollupType("H"))
.thenReturn(scmsaPosTransRollupFeedList);
List<PosHourlySt> existingPosHourlyStEntries = new ArrayList<>();
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
Mockito.when(databaseService.getDealerCodeFromPosHourly("3119255"))
.thenReturn(existingPosHourlyStEntries);
storeIdAssignmentService.processHourlyStateFeed();
assertNotNull(posHourlyStRepository.findAll());
}
}
And My StoreIdAssignmentService class will be:
#Service
public class StoreIdAssignmentService {
private StoreIdAssignmentFactory storeIdAssignmentFactory;
private DatabaseService databaseService;
#Autowired
public StoreIdAssignmentService(StoreIdAssignmentFactory storeIdAssignmentFactory,
DatabaseService databaseService) {
this.storeIdAssignmentFactory = storeIdAssignmentFactory;
this.databaseService = databaseService;
}
public void processHourlyStateFeed() {
.......................
calculateStateForPosHourlyStTransaction(posHourlyStToConsider, newPosHourlyStEntries);
.........
}
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = storeIdAssignmentFactory
.createUpdatedRollUpEntries(rollUpFeedByDealerCode);
saveAndUpdatePosHourlyStAndRollUpEntries(newPosHourlyStEntries, existingPosHourlyStEntries,
rollUpFeedByDealerCode, scmsaPosTransRollupUpdatedFlagList);
}
}
private Map<String, List<ScmsaPosTransRollup>> groupDealerCodeRollUpFeedByStoreId(
List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
// Grouping the rollUpFeedByDealerCode by storeID
return rollUpFeedByDealerCode.stream().collect(Collectors.groupingBy(ScmsaPosTransRollup::getStoreId));
}
private void calculateStateForPosHourlyStTransaction(ScmsaPosTransRollup scmsaPosTransRollupToConsider, List<PosHourlySt> newPosHourlyStEntries) {
List<PosHourlySt> posHourlyStList = newPosHourlyStEntries.stream().filter(
hourlyState -> (hourlyState.getStartDate().before(scmsaPosTransRollupToConsider.getTransactionDate())))
.collect(Collectors.toList());
..............
PosHourlySt posHourlySt=storeIdAssignmentFactory.createHourlyStEntryFromRollUp(scmsaPosTransRollupToConsider,
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(0).withMinute(0)),
Timestamp.valueOf(scmsaPosTransRollupToConsider.getTransactionDate().toLocalDateTime().withHour(23).withMinute(59)));
newPosHourlyStEntries.add(posHourlySt);
....................
}
}
and My Factory class would be:
#Component
public class StoreIdAssignmentFactory {
private static final Logger log = LoggerFactory.getLogger(StoreIdAssignmentFactory.class);
private ModelMapper modelMapper;
#Autowired
public StoreIdAssignmentFactory(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
public PosHourlySt createHourlyStEntryFromRollUp(ScmsaPosTransRollup scmsaPosTransRollup, Timestamp startDate, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(scmsaPosTransRollup.getDealerCode());
posHourlySt.setSourceJobLogId(scmsaPosTransRollup.getJobLogId());
posHourlySt.setStartDate(startDate);
posHourlySt.setStoreId(scmsaPosTransRollup.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("New Rec: {}", posHourlySt.toString());
return posHourlySt;
}
public PosHourlySt createHourlyStEntryFromPosHourlySt(PosHourlySt posHourlyStToSplit, Timestamp endDate){
PosHourlySt posHourlySt = new PosHourlySt();
posHourlySt.setDealerCode(posHourlyStToSplit.getDealerCode());
posHourlySt.setSourceJobLogId(posHourlyStToSplit.getJobLogId());
posHourlySt.setStartDate(posHourlyStToSplit.getStartDate());
posHourlySt.setStoreId(posHourlyStToSplit.getStoreId());
posHourlySt.setEndDate(endDate);
posHourlySt.setJobLogId(0L);
posHourlySt.setSource("ROLLUP");
log.info("SplitupRec: {}", posHourlySt.toString());
return posHourlySt;
}
public List<ScmsaPosTransRollup> createUpdatedRollUpEntries(List<ScmsaPosTransRollup> rollUpFeedByDealerCode) {
List<ScmsaPosTransRollup> scmsaPosTransRollupUpdatedFlagList = new ArrayList<>();
for(ScmsaPosTransRollup scmsaPosTransRollupFeed : rollUpFeedByDealerCode) {
ScmsaPosTransRollup scmsaPosTransRollupUpdateFlag = new ScmsaPosTransRollup();
modelMapper.map(scmsaPosTransRollupFeed, scmsaPosTransRollupUpdateFlag);
scmsaPosTransRollupUpdateFlag.setProcessedFlag("Y");
scmsaPosTransRollupUpdatedFlagList.add(scmsaPosTransRollupUpdateFlag);
}
return scmsaPosTransRollupUpdatedFlagList;
}
}
The StoreIdAssignmentService class contains the method "calculateStateForPosHourlyStTransaction" which calls some method in Factory class. When I debug as the junit test case , am not able to call that factory class method . What I am doing wrong here. Can anyone please suggest me.
You are mocking the factory:
#Mock
private StoreIdAssignmentFactory storeIdAssignmentFactory;
So you can't investigate the method createHourlyStEntryFromRollUp inside the factory, because the whole factory is mocked:
storeIdAssignmentFactory.createHourlyStEntryFromRollUp
If you trying to debug the createHourlyStEntryFromRollUp and the StoreIdAssignmentFactory is a #Component (or #Service), I recommend create a StoreIdAssignmentFactoryTest class test, use the #Autowired on it and #MockBean his dependencies.
Example:
#SpringBootTest
public class StoreIdAssignmentFactoryTest {
#Autowired
StoreIdAssignmentFactory factory;
#Test
public void testing() {
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp(...);
//TODO asserts and etc
}
}
But this test is considered a integration test, because it load the whole spring context and beans related.
Another alternative is the (true) unit test. Use your constructor and not use #SpringBootTest, mock the dependencies (ModelMapper). This makes the test more fast and simple.
Example:
public class StoreIdAssignmentFactoryTest {
#Test
public void testing() {
ModelMapper mapper = mock(ModelMapper.class);
StoreIdAssignmentFactory factory = new StoreIdAssignmentFactory(mapper)
List<ScmsaPosTransRollup> list = factory.createHourlyStEntryFromRollUp();
//TODO asserts and etc
}
}

#Cacheable in DAO layer not being triggered (Spring/Reddis)

I am having trouble caching internal methods within my DAO layer while in Proxy mode.
I am aware that while in Proxy mode, only external method calls coming in through the proxy are intercepted. However,I want to avoid having to switch to AspectJ mode and was wondering if any other work arounds existed.
I am displaying my code below and am wondering what changes, if any, I can add to make this process work.
--Note I am using swagger to document my code
--Also note my code has been watered down....for obvious reasons
//Controller
#RestController
#Api(produces = "application/json", protocols = "https", tags = "Securities", description = "Securities information")
public class SecuritiesInfoController extends Controller {
private SecuritiesInfoManager _securitiesInfoManager = new SecuritiesInfoManager();
#RequestMapping(value = "/security", method = RequestMethod.GET)
public List<SecuritiesInfo> getAll(){
return _securitiesInfoManager.getAll();
}
}
//Service
public class SecuritiesInfoManager extends Manager {
private SecuritiesInfoDAO _securitiesDAO = new SecuritiesInfoDAO();
public List<SecuritiesInfo> getAll() {
return _securitiesDAO.getAll();
}
}
//DAO
public class SecuritiesInfoDAO extends DAO {
private static String securitiesTable = "Securities";
#SecuritiesInfoDAOInterface
public List<SecuritiesInfo> getAll() {
//Magic
}
}
//Interface
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
#Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager",
keyGenerator="keyGenerator" )
public #interface SecuritiesInfoDAOInterface {
}
//CacheConfig
#Configuration
//#EnableCaching(mode = AdviceMode.PROXY)
#EnableCaching(proxyTargetClass = true)
//#EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
#Bean
public SecuritiesInfoDAO myService() {
// configure and return a class having #Cacheable methods
return new SecuritiesInfoDAO();
}
#Bean
public JedisConnectionFactory redisConnectionFactory() {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
// Defaults
redisConnectionFactory.setHostName("Nope");
redisConnectionFactory.setPort(LoL);
System.out.println("IN CONNTECTION");
redisConnectionFactory.setPassword("Please help me :)");
return redisConnectionFactory;
}
#Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory cf) {
System.out.println("cf: "+cf.toString());
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>();
redisTemplate.setConnectionFactory(cf);
return redisTemplate;
}
/*
#Primary
#Bean
public RedisTemplate<String,ExpiringSession> redisTemplate2(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, ExpiringSession> template = new RedisTemplate<String, ExpiringSession>();
template.setHashValueSerializer(new LdapFailAwareRedisObjectSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
*/
#Bean
public CacheManager cacheManager(RedisTemplate<String, String> redisTemplate) {
System.out.println("IN CACHE MANAGER");
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// Number of seconds before expiration. Defaults to unlimited (0)
// cacheManager.setDefaultExpiration(300);
return cacheManager;
}
#Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
#Override
public Object generate(Object o, Method method, Object... objects) {
// This will generate a unique key of the class name, the method name,
// and all method parameters appended.
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append(method.getName());
for (Object obj : objects) {
sb.append(obj.toString());
}
System.out.println(sb.toString());
return sb.toString();
}
};
}
So I figured out the answer. It turns out I wasn't implementing/instantiating the interface correctly.
First I have to #Autowire my manager class in my controller. Then #autowire my interface class in my manager.
For a more detailed solution, I am placing my revised code below.
//Controller
#RestController
#Api(produces = "application/json", protocols = "https", tags = "Securities", description = "Securities information")
public class SecuritiesInfoController extends Controller {
#Autowired
private SecuritiesInfoManager _securitiesInfoManager = new SecuritiesInfoManager();
#RequestMapping(value = "/security", method = RequestMethod.GET)
public List<SecuritiesInfo> getAll(){
return _securitiesInfoManager.getAll();
}
}
//Service
public class SecuritiesInfoManager extends Manager {
#Autowired
public void setSecuritiesInfoDAOInterface(SecuritiesInfoDAOInterface _securitiesInfoDAOInterface) {
this._securitiesInfoDAOInterface = _securitiesInfoDAOInterface;
}
public List<SecuritiesInfo> getAll() {
return _securitiesInfoDAOInterface.getAll();
}
}
//DAO
public class SecuritiesInfoDAO extends DAO implements SecuritiesInfoDAOInterface {
private static String securitiesTable = "Securities";
#Override
public List<SecuritiesInfo> getAll() {
//Magic
}
}
//Interface
public interface SecuritiesInfoDAOInterface {
#Cacheable(cacheNames = "SecuritiesInfo",cacheManager="cacheManager", keyGenerator="keyGenerator" )
List<SecuritiesInfo> getAll();
}
}
//CacheConfig
#Configuration
#EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
#Bean
public SecuritiesInfoManager myService() {
// configure and return a class having #Cacheable methods
return new SecuritiesInfoManager();
}
//rest same as before
}
//WebConfig
#Configuration
#ComponentScan(basePackages = {"package name"})
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
AntPathMatcher matcher = new AntPathMatcher();
matcher.setCaseSensitive(false);
configurer.setPathMatcher(matcher);
}
}

Spring Boot Autowiring of JsonDeserializer in Integration test

I have an application which needs a service to be Spring wired in a JsonDeserializer. The problem is that when I start up the application normally it is wired, but when I start it up in a test, it is null.
The relevant code is:
JSON Serializer/Deserializer:
#Component
public class CountryJsonSupport {
#Component
public static class Deserializer extends JsonDeserializer<Country> {
#Autowired
private CountryService service;
#Override
public Country deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
return service.getById(jsonParser.getValueAsLong());
}
}
}
Domain Object:
public class BookingLine extends AbstractEntity implements TelEntity {
.....other fields
//Hibernate annotations here....
#JsonDeserialize(using = CountryJsonSupport.Deserializer.class)
private Country targetingCountry;
..... other fields
}
Test Class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(Application.class)
#WebIntegrationTest({"server.port=0"})
#ActiveProfiles("test")
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class BookingAndLinesControllerFunctionalTest {
#Test
public void testGetBooking() {
Booking booking = bookingRepositoryHelper.createBooking();
bookingRepository.save(booking);
String uri = String.format("http://localhost:%s/api/v1/booking-and-lines/" + booking.getBookingCode(), port);
Booking booking1 = restTemplate.getForObject(uri, Booking.class); // line which falls over because countryService is null
}
}
Any ideas?
Managed to discover the answer to this one after fiddling around long enough. Just needed some config like this:
#Configuration
#Profile("test")
public class TestConfig {
#Bean
public HandlerInstantiator handlerInstantiator() {
return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
}
#Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder(HandlerInstantiator handlerInstantiator) {
Jackson2ObjectMapperBuilder result = new Jackson2ObjectMapperBuilder();
result.handlerInstantiator(handlerInstantiator);
return result;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(Jackson2ObjectMapperBuilder objectMapperBuilder) {
return new MappingJackson2HttpMessageConverter(objectMapperBuilder.build());
}
#Bean
public RestTemplate restTemplate(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) {
List<HttpMessageConverter<?>> messageConverterList = new ArrayList<>();
messageConverterList.add(mappingJackson2HttpMessageConverter);
return new RestTemplate(messageConverterList);
}
}

Categories

Resources