Springboot mockito mock a field - mockito

I want to mock the TreeMap in Service class, I tried to mock using TreeMap<String, String> requestsMap = Mockito.mock(TreeMap.class); But the map is getting null at runtime.
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class ServiceTest {
#InjectMocks
private Service service;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
TreeMap<String, String> requestsMap = Mockito.mock(TreeMap.class);
}
}
#Service
public class Service {
private TreeMap<String, String> requestsMap = null;
}

Your Service class doesn't actually do anything but declare and initialize the requestMap to null. Also, your test method doesn't do anything other than declare a mock requestMap.
In addition to the code you have, write a method in the Service that uses the request map and just declare/autowire the requestMap. In your test, use the #Mock annotation on a declaration of your mock requestMap. Finally, use the mocked requestMap in your test.
For example:
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
public class ServiceTest {
#Mock
TreeMap<String, String> requestsMap;
#InjectMocks
private Service service;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
when(requestMap.get("foo")).thenReturn("bar");
String result = service.doSomething();
assertEquals(result, "bar");
}
}
#Service
public class Service {
#Autowired
private TreeMap<String, String> requestsMap;
public String doSomething() {
return requestMap.get("foo");
}
}

Related

I can't use mockito to replace the method call in SpringBatch

I'm trying to use mockito to replace the method call in SpringBatch. The code is greatly simplified and removed unnecessary to reduce it, if something is missing, write, I will add.
Spring Batch Settings File
#Configuration
#EnableBatchProcessing
public class ListBatchConfig {
#Bean
public Job jobListBath(JobBuilderFactory jobBuilderFactory,
StepBuilderFactory stepBuilderFactory,
ItemReader<Student> itemReaderListBath,
ItemProcessor<Student, Marksheet> processorListBath,
ItemWriter<Marksheet> itemWriterListBath
) {
Step step = stepBuilderFactory.get("List-load")
.<Student, Marksheet>chunk(3)
.reader(itemReaderListBath)
.processor(processorListBath)
.writer(itemWriterListBath)
.build();
return jobBuilderFactory.get("L-Load")
.incrementer(new RunIdIncrementer())
.start(step)
.build();
}
#Bean
public ItemReader<Emaill> itemReaderListBath() {
return new ListItemReader();
}
...
The ItemReader is described in a separate class List Item Reader
#Component
#Slf4j
public class ListItemReader implements ItemReader<Student> {
#Autowired
private CalService calService ;
DataAtributes dataAtributes;
...
#Override
public Student read() {
//Тут вызывается метод сервиса, который необходимо подменить
dataAtributes = new DataAtributes(1,"test");
Integer val = calService.addAttr(dataAtributes);
...
}
Here is the service itself
#Service
public class CalService {
public int addI(int input1) {
return 0;
}
public Integer addAttr(DataAtributes attr) {
return 0;
}
}
in this service, the Job starts
#Service
public class StartJob {
#Autowired
JobLauncher jobLauncher;
#Autowired
Job jobDeveloper;
public void launchJob() throws Exception {
...
JobExecution jobExecution = jobLauncher.run(jobDeveloper, params);
and the testing class itself
#SpringBootTest
public class CaclServisTest {
#Mock
CalService calcService;
#InjectMocks
StartJob
#Autowired
StartJob startJob;
#Test
void add() {
DataAtributes dataAtributes = new DataAtributes(1,"test");
when(calcService.addAttr(dataAtributes)).thenReturn(57);
startJob.launchJob();
}
}
As a result, the native method is called, not the substituted one.
I do not understand what service should be installed #InjectMocks
Your #Mock field is not available for in Spring context.
In particular: #Autowire StartJob startJob uses CalService from Spring context, not your mock.
To replace a bean in Spring context, use #MockBean instead:
#SpringBootTest
public class CaclServisTest {
#MockBean
CalService calcService;
#Autowired
StartJob startJob;
#Test
void add() {
DataAtributes dataAtributes = new DataAtributes(1,"test");
when(calcService.addAttr(dataAtributes)).thenReturn(57);
startJob.launchJob();
}
}

how to convert return type of method within when().thenReturn method of Mockito

Below is my code snippet. This is giving me compilation error, as env.getProperty will return String. How do I get integer value. Interger.ParseInt is not working.
when(this.env.getProperty("NeededIntegerValue")).thenReturn(15);
Below is my test class
public class MyclassTest {
Myclass myObj=new Myclass();
#Mock Environment env=Mockito.mock(Environment.class);
#Before
public void init() {
when(this.env.getProperty("StringKey1")).thenReturn("Stringvalue");
when(this.env.getProperty("StringKey2")).thenReturn(intValue);
myObj.setEnvironment(this.env);
}
#Test
public void testTenantIdentifierCutomerTypeCUSTOMER_ACCOUNT() {
assertEquals("Expecteddata",myObj.testMethod(new StringBuilder(inputData),anotherData).toString);
}
}
Below is the Method needs to be tested
public StringBuilder testMethod(StringBuilder inputData, String anotherData)
{
if (anotherData.equals(env.getProperty("StringKey1"))) {
inputData=inputData.append(","+arrayOfInputData[Integer.parseInt(env.getProperty("intValue"))]);
}
}
First, you should mock your env, this way:
when(this.env.getProperty("StringKey1")).thenReturn("StringValue");
when(this.env.getProperty("StringKey2")).thenReturn("StringRepresentationOfYourInt");
Second, pay attention to the method itself, should be
arrayOfInputData[Integer.parseInt(env.getProperty("StringKey2"))
not
arrayOfInputData[Integer.parseInt(env.getProperty("intValue"))
Instead of
myObj.setEnvironment(this.env); in init() method try:
#InjectMocks
Myclass myObj = new Myclass();
Also remove assignment for
#Mock Environment env=Mockito.mock(Environment.class);
it should look
#Mock Environment env;

#SpringIntegrationTest annotation does not load context as expected

Normally, when I use #SpringBootTest I get the full context of beans. I can the #Autowire all kinds of beans that are available after the application has started.
Now, in the scope of spring-integration-test libary, the #SpringIntegrationTest does not do this.
As the testing module promises, you can use
#Autowired
private MockIntegrationContext mockIntegrationContext;
However, after inspecting the bean map on that instance, I found out there are no beans!
Example test:
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#SpringIntegrationTest
public class AppTest {
#Autowired
private MockIntegrationContext mockIntegrationContext;
#Test
public void contextLoads() {
// put breakpoint to inspect field
System.out.println(mockIntegrationContext);
}
}
When I however run the following code, I get a complete context:
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#SpringBootTest
public class App2Test {
#Autowired
private ListableBeanFactory beanFactory;
#Test
public void contextLoads() {
Assert.isTrue(beanFactory.getBeanDefinitionCount() > 0)
}
}
Why is that? How can I achieve a similar result with spring-integration-test?
Reading materials: https://docs.spring.io/spring-integration/docs/current/reference/html/testing.html
They are independent annotations; you need both.
EDIT
This works fine for me:
#RunWith(SpringRunner.class)
#SpringBootTest
#SpringIntegrationTest
public class So52297757ApplicationTests {
#Autowired
private MockIntegrationContext mockIntegrationContext;
#Autowired
private String foo;
#Test
public void contextLoads() {
System.out.println(foo);
System.out.println(mockIntegrationContext);
}
}
and
#SpringBootApplication
public class So52297757Application {
public static void main(String[] args) {
SpringApplication.run(So52297757Application.class, args);
}
#Bean
public String foo() {
return "foo";
}
}
and
foo
org.springframework.integration.test.context.MockIntegrationContext#1de5f0ef

onApplicationEvent() is never invoked on DelayHandler

I'm using Spring Boot and Spring Integration Java DSL in my #Configuration class. One of the flows is using DelayHandler with MessageStore, by means of .delay(String groupId, String expression, Consumer endpointConfigurer):
#Bean
public IntegrationFlow errorFlow() {
return IntegrationFlows.from(errorChannel())
...
.delay(...)
...
.get();
}
I was hoping to utilize the reschedulePersistedMessages() functionality of DelayHandler, but I found out the onApplicationEvent(ContextRefreshedEvent event) which invokes it is actually never invoked (?)
I'm not sure, but I suspect this is due to the fact DelayHandler is not registered as a Bean, so registerListeners() in AbstractApplicationContext is not able to automatically register DelayHandler (and registration of non-bean listeners via ApplicationEventMulticaster.addApplicationListener(ApplicationListener listener) is not done for DelayHandler.
Currently I'm using a rather ugly workaround of registering my own listener Bean into which I inject the integration flow Bean, and then invoking the onApplicationEvent() manually after locating the DelayHandler:
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
Set<Object> integrationComponents = errorFlow.getIntegrationComponents();
for (Object component : integrationComponents) {
if (component instanceof DelayerEndpointSpec) {
Tuple2<ConsumerEndpointFactoryBean, DelayHandler> tuple2 = ((DelayerEndpointSpec) component).get();
tuple2.getT2().onApplicationEvent(event);
return;
}
}
}
Well, yes. This test-case confirm the issue:
#ContextConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
#DirtiesContext
public class DelayerTests {
private static MessageGroupStore messageGroupStore = new SimpleMessageStore();
private static String GROUP_ID = "testGroup";
#BeforeClass
public static void setup() {
messageGroupStore.addMessageToGroup(GROUP_ID, new GenericMessage<>("foo"));
}
#Autowired
private PollableChannel results;
#Test
public void testDelayRescheduling() {
Message<?> receive = this.results.receive(10000);
assertNotNull(receive);
assertEquals("foo", receive.getPayload());
assertEquals(1, messageGroupStore.getMessageGroupCount());
assertEquals(0, messageGroupStore.getMessageCountForAllMessageGroups());
}
#Configuration
#EnableIntegration
public static class ContextConfiguration {
#Bean
public IntegrationFlow delayFlow() {
return flow ->
flow.delay(GROUP_ID, (String) null,
e -> e.messageStore(messageGroupStore)
.id("delayer"))
.channel(c -> c.queue("results"));
}
}
}
Here we go: https://github.com/spring-projects/spring-integration-java-dsl/issues/59.
As a workaround we can do this in our #Configuration:
#Autowired
private ApplicationEventMulticaster multicaster;
#PostConstruct
public void setup() {
this.multicaster.addApplicationListenerBean("delayer.handler");
}
Pay attention to the beanName to register. This is exactly that .id("delayer") from our flow definition plus the .handler suffix for the DelayHandler bean definition.

Mockito - Testing method that calls private methods

I was trying to find solution but haven't found yet. I tried to test public method which has calls of the couple of private ones inside. One of the problem that private method retrieves Hibernate's Criteria by generic method that in its turn retrieves it through chain of another generic methods. Please take a look at the code below. Frankly I'm not sure that it is possible to test that case but if anyone has ideas please suggest them:
ConcreteDao
public class ConcreteDao extends EntityDao<ConcreteEntity> {
public Class<ConcreteEntity> getClassType() {
return ConcreteEntity.class;
}
}
EntityDao
public abstract class EntityDao<T> extends AbstractDao<T>{
public List<T> getEntityByFilter(EntityFilter filter) {
Criteria criteria = getCriteriaByFilter(filter.getFilters());
criteria.setMaxResult(filter.getMaxResult());
criteria.setFirstResult(filter.getFirstResult());
criteria.addOrder(Order.asc(filter.getSortedField()));
criteria.list();
}
private Criteria getCriteriaByFilter(List<CustFilter> filters) {
Criteria criteria = getCriteria();
for (CustFilter filter : filters) {
filter.addrestrictionToCriteria(criteria, filter.getProperty(), filter.getValue());
}
return criteria;
}
}
AbstractDao
public abstract class AbstractDao<T> {
private EntityManagerFactory entityManagerFactory;
public abstract getClassType();
public Criteria getCriteria() {
return getSession().createCriteria(getClassType());
}
public Session getSession() {
Session session = (Session) getEntityManager().getDelegate();
return session;
}
public EntityManager getEntityManager() {
entityManagerFactory.getEntityManager();
}
}
Test class
#RunWith(MockitoJUnitRunner.class)
public class ConcreteDaoTest {
#Mock
private EntityManager entityManager;
#Mock
private Session session;
#Mock
private Criteria criteria;
private List<CustFilter> filters;
private EntityFilter entityFilter;
private List<ConcreteEntity> resultList;
#InjectMocks
private ConcreteDao concreteDao = new ConcreteDao;
public void init() {
filters = new ArrayLis<CustFilter>();
CustFilter custFilter = new CustFilter();
//fill filter;
filters.add(custFilter);
entityFilter = new EntityFilter();
//fill entityFilter
entityFilter.setFilters(filters);
ConcreteEntity concreteEntity = new ConcreteEntity();
resultList = new ArrayList<ConcreteEntity>();
resultList.add(concreteEntity);
}
#Test
public void getEntityByFilterTest() {
when(concreteDao.getEntityManager).thenReturn(entityManager);
when(concreteDao.getSession()).thenReturn(session);
when(concretedao.getCriteria()).thenReturn(criteria);
when(filter.getFilters()).thenReturn(filters);
when(filter.getMaxResult()).thenReturn(10);
when(filter.getFirstResult()).thenReturn(0);
when(filter.getSortedField()).thenReturn("firstName");
when(criteria.list()).thenReturn(resultList);
List<ConcreteEntity> result = concreteDao.getEntityByFilter(entityFilter);
Assert.assertThen(result. is(notNullValue()));
}
}
With Mockito, you cannot mock private method calls.
Try PowerMockito with which you can mock any kinds of methods like static methods, private methods, local method instantiations and so on.

Resources