#PostContruct method does not work with Mockito - java

Hi I am trying to initialize a field with #PostConstruct method but in tests, this method does not fill the bidiMap field.
Is there any way to mock bidiMap field which is a field of DataSource ?
#Component
#Getter
#Setter
#NoArgsConstructor
public class DataSource {
public DualHashBidiMap<String, String> bidiMap = new DualHashBidiMap();
#PostConstruct
public void loadData() throws IOException {
Map<String, String> data = new ObjectMapper().readValue(new File("src/main/resources/static/data.json"), Map.class);
data.entrySet().stream().forEach(item -> this.bidiMap.put(item.getKey(), item.getValue()));
}
}
Test:
#Test
void shouldReturnPrettifiedUrl_WithQueryParams() throws IOException {
// Given
List<String> inputParameters = Arrays.asList("/products?gender=female&tag=123&tag=1234");
HashMap<String, String> expectedResult = PrettyUrlResponseBuilder.PrettyUrlResponseBuilder().createPrettyUrlResponseWithParams();
HashMap<String, String> databaseResponse = DatabaseResponse.DatabaseResponse().createDatabaseResponse();
System.out.println(dataSource);
// When
Map<String, String> actualResult = prettyUrlService.toPretty(inputParameters);
// Then
assertEquals(expectedResult, actualResult);
}
The class being tested:
#Service
public class PrettyUrlService {
private final DataSource dataSource;
public PrettyUrlService(DataSource dataSource) {
this.dataSource = dataSource;
}
public Map<String, String> toPretty(List<String> urlList) throws IOException {
var data = dataSource.getBidiMap(); // Here, data is null.
// ...
}
}

If you're unit testing the PrettyUrlService class then you should not need to also test the underlying DataSource class within the same test. Simply mocking the DataSource interactions and verifying that all the expected interactions are happening should be more than enough.
E.g. (assuming JUnit 5):
#ExtendWith(MockitoExtension.class)
class PrettyUrlServiceTest {
#Mock
private DataSource dataSource;
private PrettyUrlService prettyUrlService;
#BeforeEach
void setUp() {
prettyUrlService = new PrettyUrlService(dataSource);
}
#Test
void exampleTest() {
DualHashBidiMap<String, String> bidiMap = new DualHashBidiMap();
// add test data to the map
bidiMap.put("testKey", "testValue"); // replace with data you need for test
Mockito.when(dataSource.getBidiMap()).thenReturn(bidiMap);
// insert test logic here (prettyServiceUrl call + assertions)
// ...
// finally, verify that dataSource.getBidiMap() was called exactly once
Mockito.verify(dataSource).getBidiMap();
}
}

Related

Override bean in test with non-mocked bean

I want to unit test a class that uses a named spring bean of a List, but I can't figure out how to override the bean with my own test bean filled with mocks.
The class that defines the named bean:
#Configuration
#RequiredArgsConstructor
public class JmsReceiveConfig {
#Bean(name = "FooConsumers")
List<JmsConsumer> messageConsumers(QueuedReceiveService fooMessageListener) throws Exception {
List<JmsConsumer> list = new ArrayList<>();
for (MyJmsProperties.Broker broker : myJmsProperties.getBrokers()) {
JmsConsumer jmsConsumer =
messageConsumer(broker, myJmsProperties.getKeystore(), myJmsProperties.getKeystorePassword(),
myJmsProperties.getTruststore(), myJmsProperties.getTruststorePassword(), fooMessageListener);
list.add(jmsConsumer);
}
return list;
}
...
}
My class that uses the named bean:
#Component
#ConditionalOnEnabledHealthIndicator("barIndicator")
#RequiredArgsConstructor
public class MyHealthIndicator implements HealthIndicator {
#Inject
#Qualifier("FooConsumers")
private List<JmsConsumer> jmsConsumersList;
#Override
public Health health() {
int connectedCount = 0;
Map<String, Object> detailsMap = new HashMap<>();
for (JmsConsumer consumer : jmsConsumersList) {
if (consumer.isConnected()) {
connectedCount++;
}
detailsMap.put(consumer.getAlias(), consumer.isConnected());
}
return Health.up()
.withDetails(detailsMap)
.build();
}
}
I tried this test class:
#ExtendWith(SpringExtension.class)
public class MyHealthIndicatorTest {
private MyHealthIndicator myHealthIndicator;
#Mock
JmsConsumer jmsConsumer1;
#Mock
JmsConsumer jmsConsumer2;
#Bean(name = "FooConsumers")
List<JmsConsumer> messageConsumers(QueuedReceiveService fooMessageListener) throws Exception {
ArrayList<JmsConsumer> jmsConsumers = new ArrayList<>();
jmsConsumers.add(jmsConsumer1);
jmsConsumers.add(jmsConsumer2);
return jmsConsumers;
}
#BeforeEach
public void setup() throws Exception {
myHealthIndicator = new MyHealthIndicator();
}
#Test
public void testStatusUpAll() {
Mockito.when(jmsConsumer1.getAlias())
.thenReturn("jmsConsumer1");
Mockito.when(jmsConsumer1.isConnected())
.thenReturn(true);
Mockito.when(jmsConsumer2.getAlias())
.thenReturn("jmsConsumer2");
Mockito.when(jmsConsumer2.isConnected())
.thenReturn(true);
Health healthCheck = myHealthIndicator.health();
assertEquals(healthCheck.getStatus(), Status.UP);
}
}
I expected the named bean I defined in the test class to be used in the #Test method inside the myHealthIndicator.health() call, but instead when that call runs, the jmsConsumers list within it is null, giving a NullPointerException on the for (JmsConsumer consumer : jmsConsumersList) line.
I also tried using a mock JmsReceiveConfig so I could change my #BeforeEach to:
List<JmsConsumer> jmsConsumers = new ArrayList<>();
jmsConsumers.add(jmsConsumer1);
jmsConsumers.add(jmsConsumer2);
Mockito.when(jmsReceiveConfig.messageConsumers(Mockito.any(QueuedReceiveService.class)))
.thenReturn(jmsConsumers);
radItsHealthIndicator = new RadItsHealthIndicator();
but I still get the same NPE exception in the same spot.
Don't bother using SpringExtension, just use MockitoExtension.
Give MyHealthIndicator a constructor which sets jmsConsumersList.
So setup becomes:
#BeforeEach
public void setup() throws Exception {
ArrayList<JmsConsumer> jmsConsumers = new ArrayList<>();
jmsConsumers.add(jmsConsumer1);
jmsConsumers.add(jmsConsumer2);
myHealthIndicator = new MyHealthIndicator(jmsConsumers);
}
The rest of your test can stay the same (of course you don't need messageConsumers().)

Java: How to Mock a protected method inside a static child class

I am having a protected method inside a static child class. I am running a testcase , its getting successful but code coverage is not increasing.
public class A{
private static final String var1 = "key1";
protected static class B extends OsCmd{
private String abc1;
private String abc2;
protected B(String xyz, String xyz2) {
this.abc1 = xyz;
this.abc2 = xyz2;
}
#Override
protected void updateEnv(Map<String, String> env) {
env.put(VAR1, "FALSE");
env.put(VAR2, "TRUE");
env.put("key3", abc1);
env.put("key4", abc2);
}
}
}
Below is my test case
#ExtendWith(MockitoExtension.class)
public class ATest {
private A mockA;
#BeforeEach
public void setup() {
mockA = Mockito.spy(A.class);
}
#Test
public void test2() {
try (MockedConstruction mockedConstruction =
mockConstruction(A.B.class)) {
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
A.B mockB =
new A.B("a", "b");
//doNothing().when(mockB).updateEnv(map);
mockB.updateEnv(map);
}
}
}
Can someone please help here, what mistake i am doing?
When you mock the constructor, then all internal method calls are also mocked and do not go through the actual code.
If you remove the following try-with-resources:
try (MockedConstruction mockedConstruction =
mockConstruction(A.B.class))
The real code will be executed and the coverage will increase.

Mocking if condition using Mockito in springboot

How can I mock this condition using Mockito in spring boot.
#Autowired
private Config config;
if (!config.getAllowedFileFormats().contains(FilenameUtils.getExtension(multipartFile.getOriginalFilename()) {
}
I tried using this but this seems to not be working.
#Mock
private Config config; Mockito.when(config.getAllowedFileFormats().contains(Mockito.anyString())).thenReturn(Boolean.valueOf(true));
Any Solutions.
Functionally your code is exactly the same as the following:
static class SomeClass {
#Autowired
private Config config;
void method(MultipartFile multipartFile) {
String filename = multipartFile.getOriginalFilename();
Set<String> allowedFormats = config.getAllowedFileFormats();
if (!allowedFormats.contains(FilenameUtils.getExtension(filename))) {
}
}
}
So you can either:
Mock every method in the chain:
#Test
void test() {
Set<String> allowedFormats = new HashSet<>();
allowedFormats.add(".exe");
MultipartFile multipartFile = /* get your file here */ ;
Mockito.when(multipartFile.getOriginalFilename()).thenReturn("some.exe");
Mockito.when(config.getAllowedFileFormats()).thenReturn(allowedFormats);
myClass.method(multipartFile);
//verify
}
You can also static mock FilenameUtils.getExtension( but imo that's pointless as it's a helper without side effects.
Or you can pull that out into a separate method and just mock that.
#Test
void test() {
SomeClass myClassSpy = Mockito.spy(new SomeClass());
MultipartFile multipartFile = /* get your file here */ ;
Mockito.when(myClassSpy.verifyAllowedFormat(multipartFile)).thenReturn(true);
myClassSpy.method(multipartFile);
//verify
}
static class SomeClass {
#Autowired
private Config config;
void method(MultipartFile multipartFile) {
if (!verifyAllowedFormat(multipartFile);) {
}
}
boolean verifyAllowedFormat(MultipartFile file) {
return config.getAllowedFileFormats()
.contains(FilenameUtils.getExtension(multipartFile.getOriginalFilename()));
}
}

Mock returns Wrong Collection

I want to return a filled Map with my mocked Object, but the size of the Map is always Null. The mocked Object "CommandLineValues options" is not Null and also the Boolean variable "doCleanFirst" I can mock successfully.
Here is my Testclass:
#RunWith(MockitoJUnitRunner.class)
public class IndexBMECatTest {
#InjectMocks
private IndexBMECat classUnderTest;
#Mock
private CommandLineValues options;
#Test
public void testAccessoryItemHasNoDublicates() {
Map<String, String> testMap = new HashMap<>();
testMap.put("key", "value");
when(options.getCleanFirst()).thenReturn(false);
when(options.readWhitlist()).thenReturn(testMap);
classUnderTest.run();
}
}
Here is the constructor of my class where the code start, the tested Method is not relevant:
private boolean doCleanFirst;
private Map<String, String> whiteList;
public IndexBMECat(TransportClient client, CommandLineValues options, BMECatReader reader) throws Exception {
this.doCleanFirst = options.getCleanFirst();
this.whiteList = options.readWhitlist();
if (whiteList.isEmpty()) {
throw new Exception("Missing whiteList");
}
}
I also tried other variants:
Mock the Map and the return value of the method "isEmpty"
Initialize the Testclass and give the mocked Object to the constructor
But the whiteList has always the size = 0
Thx, this works now:
private IndexBMECat classUnderTest;
#Mock
private CommandLineValues options;
#Mock
private BMECatReader reader;
#Mock
TransportClient client;
#Before
public void setUp() throws Exception {
Map<String, String> testMap = new HashMap<>();
testMap.put("key", "value");
when(options.getCleanFirst()).thenReturn(false);
when(options.readWhitlist()).thenReturn(testMap);
classUnderTest = new IndexBMECat(client, options, reader);
}
#Test
public void testAccessoryItemHasNoDublicates() {
classUnderTest.run();
}
First I mock the methods which will be executed in the contructor and then I create the instance of my testclass.

Spring JUnit + Mockito + In memory Database (H2)

I'm currently using Mockito and In memory Database (H2) in order to test some services and dao.
I've tried to test a method (createRoad) of my service that contains some call of dao method :
#Service(value = "RoadsService")
public class RoadsService implements IRoadsService {
#Autowired
private IRoadsDao roadsDao;
...
#Override
public long createRoad(CreateRoadCriteria criteria) {
String roaCodeToCopy = "";
RoadsCriteria roadsCriteria = new RoadsCriteria();
roadsCriteria.setCe(criteria.getCe());
roadsCriteria.setDeliveryDate(new Date());
List<WebRoadsModel> listRoadsCe = roadsDao
.getRoadsByCEAndDeliveryDate(roadsCriteria);
for (WebRoadsModel wrm : listRoadsCe) {
if (wrm.getRoaCode().endsWith("90")) {
roaCodeToCopy = wrm.getRoaCode();
break;
}
}
criteria.setRoadCode(StringUtils.substring(roaCodeToCopy, 0, 4)
+ criteria.getRoadCode());
// 2. Creation of the new road
long idNewRoad = roadsDao.createNewRoad(criteria);
if (!"".equals(roaCodeToCopy) && listRoadsCe.get(0) != null) {
roaCodeToCopy = listRoadsCe.get(0).getRoaCode();
// 3. Copy dates closed of this trn
RoadsCriteria newRoadCreated = new RoadsCriteria();
newRoadCreated.setCe(criteria.getCe());
newRoadCreated.setRoadId(idNewRoad);
// 4. Paste it for the new road
deliveryCalendarDao.copyClosedDates(roadsDao
.getRoadByCriteria(newRoadCreated).get(0).getRoaCode(),
roaCodeToCopy);
}
return idNewRoad;
}
...
}
I need to mock the method called getRoadsByCEAndDeliveryDate, because the sql query behind that is not managed by the H2 driver (query with "RANK"). Then, I want to use H2 with the other method in this service.
I've tried this :
public class RoadsServiceTest {
#InjectMocks
private RoadsService roadsService;
#Mock
private MockRoadDao roadsDao;
#BeforeClass
public static void setUpClass() throws Exception {
}
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void createRoad(){
CreateRoadCriteria criteria = new CreateRoadCriteria();
criteria.setRoadCode("AA");
criteria.setRoadName("ANAME");
criteria.setCe("2");
criteria.setDriver(1);
criteria.setVehicle(1);
criteria.setSupplier(1);
List<WebRoadsModel> expected = new ArrayList<WebRoadsModel>();
Mockito.when(roadsDao.getRoadsByCEAndDeliveryDate((RoadsCriteria) Mockito.any())).thenReturn(expected);
Mockito.when(roadsDao.getNextVal(Mockito.anyString())).thenCallRealMethod();
Mockito.when(roadsDao.createNewRoad(criteria)).thenCallRealMethod();
long result = roadsService.createRoad(criteria);
Assert.assertEquals(5, result);
}
}
It is almost good except the assertEquals.
According to my sql file used with my in memory database, i have a sql sequence like this :
CREATE SEQUENCE "SEQ_SITI_ROADS" MINVALUE 1 MAXVALUE 99999 INCREMENT BY 1 START WITH 5 CACHE 20 ;
When I run my test, the result is 0.
It seems that the MockRoadDao is not initialized.
public class MockRoadDao extends RoadsDao {
public MockRoadDao() throws DatabaseUnitException, SQLException, MalformedURLException {
IDataSet dataSet = new FlatXmlDataSetBuilder().build(new File("./src/test/resources/dataset.xml"));
DataSource dataSource = TestUtils.dataSource();
IDatabaseConnection dbConn = new DatabaseDataSourceConnection(dataSource);
DatabaseOperation.CLEAN_INSERT.execute(dbConn, dataSet);
User user = new User();
user.setLangCountry("ENFR");
BackendContextHolder.setBackendIdentifier(new BackendIdentifierImpl(user));
final NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
setJdbcTemplate(jdbcTemplate);
}
}
public class TestUtils {
private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
public static DataSource datasource;
/**
* #return
*/
public static DataSource dataSource() {
if (datasource == null) {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.setType(EmbeddedDatabaseType.H2).addScript("classpath:/siti-create.sql").build();
datasource = db;
}
return datasource;
}
...
}
Could you please help me :)
Thank you in advance
Edit :
#Baski : When I remove #Mock and use ReflectionUtils instead, the constructor of MockRoadDAO is called. But, when I run the test, the method roadsDao.getRoadsByCEAndDeliveryDate() is not mocked with Mockito, the method is really called and unfortunately the SQL query is not managed by the H2 driver.
public class RoadsServiceTest {
#InjectMocks
private RoadsService roadsService;
private MockRoadDao roadsDao;
#BeforeClass
public static void setUpClass() throws Exception {
}
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
roadsDao = new MockRoadDao();
ReflectionTestUtils.setField(roadsService, "roadsDao", roadsDao);
}
#Test
public void createRoad(){
CreateRoadCriteria criteria = new CreateRoadCriteria();
criteria.setRoadCode("AA");
criteria.setRoadName("ANAME");
criteria.setCe("2");
criteria.setDriver(1);
criteria.setVehicle(1);
criteria.setSupplier(1);
List<WebRoadsModel> expected = new ArrayList<WebRoadsModel>();
Mockito.when(roadsDao.getRoadsByCEAndDeliveryDate((RoadsCriteria) Mockito.any())).thenReturn(expected);
Mockito.when(roadsDao.getNextVal(Mockito.anyString())).thenCallRealMethod();
Mockito.when(roadsDao.createNewRoad(criteria)).thenCallRealMethod();
long result = roadsService.createRoad(criteria);
Assert.assertEquals(5, result);
}
}

Categories