mockito when method returns null in junit - junit

I have been writing the test cases using the mockito. the below is my code in the test cases.
#RunWith(SpringRunner.class)
public class LoginControllerTest {
private MockMvc mockMvc;
#InjectMocks
private LoginService loginService;
#Mock
private LoginController loginController;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
// Setup Spring test in standalone mode
mockMvc = MockMvcBuilders.standaloneSetup(loginController).build();
}
#Test
public final void test() throws Exception {
// Assign
when(loginService.test()).thenReturn("hello");
// act
mockMvc.perform(get("/hello"))
// Assertion
.andExpect(status().isOk())
.andExpect(content().string("Message from service: hello"));
verify(loginService).test();
}
#Test
public final void usernameInvalidAndPassword() throws Exception {
User userData = new User();
userData.setUserName("akhila.s#cloudium.io");
userData.setPassword("Passw0rd");
User userDataNew = new User();
userDataNew.setUserName("akhila.s#cloudium.io");
userDataNew.setPassword("Passw0rd");
JSONObject requestBody = new JSONObject();
requestBody.put("userName", "akhila.s#cloudium.io");
requestBody.put("password", "Passw0rd");
JSONObject responseBody = new JSONObject();
responseBody.put("status_code", "200");
responseBody.put("message", "ok");
// Assign
when(loginService.saveUser(userData)).thenReturn(userDataNew);
// act
mockMvc.perform(get("/login")
.param("userName", "akhila.s#cloudium.io")
.param("password", "Passw0rd"))
// Assertion
.andExpect(status().isOk()).andExpect(content().json(responseBody.toString())).andDo(print());
}
For the first test case its working fine but for the second test it is returning null always. Can anyone please help? Thanks in advance

You have the annotations the wrong way round on your LoginController and LoginService. You are testing the controller so you don't want to mock it, and you are stubbing methods on your service so this needs to be a mock:
#Mock
private LoginService loginService;
#InjectMocks
private LoginController loginController;

In my opinion you have to either:
1) Introduce equals method based on username and password as the User object created inside the method under test is a different instance than the one you create and use in the test.
2) Use a wildcard in your set-up:
when(loginService.saveUser(Mockito.any(User.class))).thenReturn(userDataNew);

Related

Intgration Test in springboot pass when test at each method but fail when running class

It seems pass when a run the test individually but fine when fair when running the class .I have tried to use #Before and #After annotatoon.And only the Dirtiescontext most fit my case.My question is any alternative for dirtiescontext(too slow) or any method can suit my case?
My test code:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#AutoConfigureMockMvc
class UserCoreControllerTest {
#Autowired
private UserRepository userRepository;
#Autowired
private UserCoreService userCoreService;
#Autowired
private ObjectMapper objectMapper;
#Autowired
private MockMvc mockMvc;
/*
*//* #BeforeTestMethod
public void setUp(){
System.out.println("begin");
userRepository.save(mockUser());
}
#AfterTestMethod
public void tearOff(){
System.out.println("end");
userRepository.deleteById(1);
}
*/
private User mockUser(){
User user= new User(0,"admin","admin",null,null,"yl","sd"
,"434","dsf",null,4,2,new ArrayList<>());
user.getApplications().add(mockJobOrder("job1title","b"));
user.getApplications().add(mockJobOrder("job2title","d"));
return user;
}
private JobOrder mockJobOrder(String title,String des){
return new JobOrder(0,1,title,des,null,null,0,2,false,0,null);
}
#Test
void getProfile() throws Exception {
userRepository.save(mockUser());
mockMvc.perform(get("/UserJob/getProfile/{id}", 1)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.username")
.value("admin"))
.andDo(print());
}
#Test
void getUserByName() throws Exception {
userRepository.save(mockUser());
mockMvc.perform(get("/UserJob/get/Byusername/{username}", "admin")
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.password").value("admin"));
//if cant found user
MvcResult whatever = mockMvc.perform(get("/UserJob/get/Byusername/{username}", "whatever")
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andReturn();
Assertions.assertEquals("",whatever.getResponse().getContentAsString());
}
#Test
void updateUser() throws Exception {
userRepository.save(mockUser());
User updated=new User(1,"alex","admin",null,null,"yl","sd"
,"434","dsf",null,4,2,null);
String request=objectMapper.writeValueAsString(updated);
MvcResult mvcResult=mockMvc.perform(MockMvcRequestBuilders.put("/UserJob/updateuser")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON_VALUE)
.content(request)
)
.andExpect(status().isOk())
.andDo(print())
.andReturn();
Assertions.assertEquals("Successful update",mvcResult.getResponse().getContentAsString());
mockMvc.perform(get("/UserJob/getProfile/{id}", 1)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.username")
.value("alex"))
.andDo(print());
}
#Test
void showApplicationshistory() throws Exception {
userRepository.save(mockUser());
mockMvc.perform(get("/UserJob/application/history/{id}", 1)
.accept(MediaType.APPLICATION_JSON_VALUE)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].title").value("job1title"))
.andExpect(jsonPath("$[1].title").value("job2title"))
.andDo(print());
}
#Test
void addUser() throws Exception {
User user=mockUser();
user.setUsername("tom");
String request=objectMapper.writeValueAsString(user);
mockMvc.perform(MockMvcRequestBuilders.post("/UserJob/add/user")
.contentType(MediaType.APPLICATION_JSON)
.content(request)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isOk())
.andExpect(jsonPath("$.username").value("tom"));
}
Application properties(i test it on a real database with drop-create)
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=*
spring.datasource.password=*
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.defer-datasource-initialization=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
spring.sql.init.mode=always
logging.level.root=INFO
I guess that the test are failing because of some user constraints - since you insert the user a multiple times here.
There are multiple solutions for that.
Mark your test as transactional. The transaction is automatically rollbacked for tests.
Clear the tables manually after/before each test. Either by using the repository.deleteAll() or truncate the whole db with some sql statements.
Just as a side information: You can also use testcontainers instead of having a persistente database locally. See https://www.testcontainers.org/ or even better: a wrapper library around it: https://github.com/PlaytikaOSS/testcontainers-spring-boot

How to Mock microservices in Junit

I need to run the integration test of one microservice, without the need to start the dependent microservices.
Below is the approach I have tried(I have provided the skeleton of the classes below)
MicroServiceOneController.java
#Autowired
MicroServiceOneService microServiceOneServiceImpl;
#PostMapping(value = "/saveData/{userEmail}")
public void doHandleSaveData(
#PathVariable("userEmail") String userEmail) {
microServiceOneService.saveData(userEmail);
}
MicroServiceOneServiceImpl.java
#Autowired
MicroServiceTwoProxy microServiceTwoProxy;
#Override
public void saveData(String userEmail){
DemoDTO dtoObject=microServiceTwoProxy.fetchRequiredData();
dtoObject.setUserEmail(userEmail);
// other code to persist dtoObject
}
TestOfMicroServiceOne.java:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class TestOfMicroServiceOne{
#Autowired
private TestRestTemplate restTemplate;
#MockBean
MicroServiceTwoProxy microServiceTwoProxy;
#test
void test(){
Mockito.when(microServiceTwoProxy.fetchRequiredData()).thenReturn(new DemoDTO("1","data"));
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<DemoDTO.class> response =
this.restTemplate.exchange("/persist/saveData/{userEmail}",
HttpMethod.POST, entity, DemoDTO.class, "user#gmail.com");
assertEquals(response.getStatusCode(), HttpStatus.OK);
}
I expected when running the test, when the microServiceTwoProxy.fetchRequiredData() is hit, it should return the new DemoDTO("1","data") as specified in the test.
I want this requirement to run the test of MicroserviceOne without depending upon the status of MicroServiceTwo.
But this doesn't seem to work. It expects the second microservices to be up and test fails with the message Load balancer does not have available server for client
Any other approaches available?

How to mock ObjectMapper.readValue() using mockito

I'm testing a service layer and not sure how to mock ObjectMapper().readValue in that class. I'm fairly new to mockito and could figure out how to do it.
The following is my code,
service.java
private configDetail fetchConfigDetail(String configId) throws IOException {
final String response = restTemplate.getForObject(config.getUrl(), String.class);
return new ObjectMapper().readValue(response, ConfigDetail.class);
}
ServiceTest.java
#Test
public void testgetConfigDetailReturnsNull() throws Exception {
restTemplate = Mockito.mock(restTemplate.class);
Service service = new Service();
Config config = Mockito.mock(Config.class);
ObjectMapper objMapper = Mockito.mock(ObjectMapper.class);
Mockito.doReturn("").when(restTemplate).getForObject(anyString(), eq(String.class));
Mockito.doReturn(configDetail).when(objMapper).readValue(anyString(),eq(ConfigDetail.class));
assertEquals(configDetail, service.getConfigDetail("1234"));
}
I get the following results when I run this test,
com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input
at [Source: (String)""; line: 1, column: 0]
Posting ServiceTest.Java here
#RunWith(MockitoJUnitRunner.class)
public class ConfigServiceTest {
#Mock
private ConfigPersistenceService persistenceService;
#InjectMocks
private ConfigService configService;
#Mock
ConfigDetail configDetail;
#Mock
private RestTemplate restTemplate;
#Mock
private ObjectMapper objMapper;
#Mock
private Config config;
#Test
public void testgetConfigDetailReturnsNull() throws Exception {
ObjectMapper objMapper = Mockito.mock(ObjectMapper.class);
Mockito.doReturn(ucpConfig).when(persistenceService).findById("1234");
Mockito.doReturn("").when(restTemplate).getForObject(anyString(), eq(String.class));
Mockito.when((objMapper).readValue(“”,ConfigDetail.class)).thenReturn(configDetail);
assertEquals(ConfigDetail, ConfigService.getConfigDetail("1234"));
}
}
With your current Service class it would be difficult to mock ObjectMapper, ObjectMapper is tightly coupled to fetchConfigDetail method.
You have to change your service class as follows to mock ObjectMapper.
#Service
public class MyServiceImpl {
#Autowired
private ObjectMapper objectMapper;
private configDetail fetchConfigDetail(String configId) throws IOException {
final String response = restTemplate.getForObject(config.getUrl(), String.class);
return objectMapper.readValue(response, ConfigDetail.class);
}
}
Here what I did is instead of creating objectMapper inside the method I am injecting that from outside (objectMapper will be created by Spring in this case)
Once you change your service class, you can mock the objectMapper as follows.
ObjectMapper mockObjectMapper = Mockito.mock(ObjectMapper.class);
Mockito.when(mockObjectMapper.readValue(anyString(), any(ConfigDetail.class)).thenReturn(configDetail);
Problem is with the this line where you are mocking the call to objectmapper.
Mockito.when((objMapper).readValue(“”,ConfigDetail.class)).thenReturn(configDetail);
Correct syntax is
Mockito.when(objMapper.readValue(“”,ConfigDetail.class)).thenReturn(configDetail);
Notice the bracket position. When using Spy or Verify, the bracket position is diff. then when using when-then syntax.
Mocking objects created in a SUT is IMO the single biggest limitation of mockito. Use jmockit or powerMock or checkout the offical mockito way of handling this. https://github.com/mockito/mockito/wiki/Mocking-Object-Creation

Can any one help me in mocking a static method which returns an object, and this static method is present in a final class

I need help for below thing,
I have to write a Junit using PowerMock/Mockito for a method which makes a call to a static method of a final class present in an external jar.
The method for which i need to write the JUnit test is:
public class SomeClass {
private PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException {
Reader reader = new StringReader(privateKeyPem);
Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY");
if (section == null) {
throw new IOException("Invalid PKCS8 data.");
}
byte[] bytes = section.getBase64DecodedBytes();
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes);
try {
KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory();
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
} catch (NoSuchAlgorithmException exception) {
} catch (InvalidKeySpecException exception) {
}
throw new IOException("Unexpected exception reading PKCS data");
}
}
In the above code PemReader is a final class and readFirstSectionAndClose(reader, "PRIVATE KEY") is a static method in PemReader.
I have tried writing the test shown below but Section object(section) is showing as null while debugging. Perhaps the actual code (PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY")) is getting called instead of the mock.
#RunWith(PowerMockRunner.class)
#PrepareForTest({SomeClass.class,PemReader.class})
public class SomeClassTest {
#InjectMocks
SomeClass mockSomeClass;
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testPrivateKeyFromPkcs8() throws Exception {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
assertNotNull(mockSomeClass.privateKeyFromPkcs8(dummyPrivateKey));
}
}
Please help me in writing a Junit using powermockito/mockito
You have to prepare the final, static class.
Here's an example using the PowerMock annotations for JUnit:
#RunWith(PowerMockRunner.class)
#PrepareForTest({PemReader.class})
public class PemReaderTest {
#Mock
private Reader mockReader;
#Mock
private Section mockSection;
#Test
public void testMockingStatic() {
PowerMockito.mockStatic(PemReader.class);
Mockito.when(PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY")).thenReturn(mockSection);
Assert.assertEquals(mockSection, PemReader.readFirstSectionAndClose(mockReader, "PRIVATE KEY"));
}
}
For completeness, here's the definition of PemReader:
public final class PemReader {
public static Section readFirstSectionAndClose(Reader reader, String key) {
return null;
}
}
The above test passes with the following versions:
JUnit: 4.12
Mockito: 2.7.19
PowerMock: 1.7.0
Update 1: based on your updated question. Your test case will pass (or at least the invocation on PemReader.readFirstSectionAndClose will return something) if you just make this change:
Mockito.when(PemReader.readFirstSectionAndClose(
Mockito.any(Reader.class),
Mockito.eq("PRIVATE KEY"))
).thenReturn(mockSection);
The version of this instruction in your current test case relies on equality matching between the StringReader which your code passes into readFirstSectionAndClose and the mocked Reader which your test case supplies. These are not 'equal' hence the mocked invocation's expectations are not met and your mockSection is not returned.
A few, unrelated, notes:
There is no need to include SomeClass.class in #PrepareForTest, you only need to include the classes which you want to mock in that annotation, since SomeClass is the class you are trying to test there is no mocking required for that class.
Using #InjectMocks to instance SomeClass is a bit odd, since SomeClass has no (mockito provided) mocks to inject into it :) you can replace this declaration with SomeClass someClass = new SomeClass();
In the code you supplied SomeClass.privateKeyFromPkcs8 has private scope so it cannot be tested (or called in any way) from SomeClassTest.

Unable to mock a method

I am new to JUNITS and have been trying to use Mockito and PowerMockito for writing some test cases for my code but have been facing an issue.
Class Code:
public class Example implements Callable<Void> {
int startIndex;
int endIndex;
ConnectionPool connPool;
Properties properties;
public Example(int start, int end,
ConnectionPool connPool, Properties properties) {
this.startIndex = start;
this.endIndex = end;
this.connPool= connPool;
this.properties = properties;
}
#Override
public Void call() throws Exception {
long startTime = System.currentTimeMillis();
try {
List<String> listInput = new ArrayList<>();
Service service = new Service(
dbConnPool, properties, startIndex, endIndex);
service.getMethod(listInput);
.
.
.
JUNIT Code:
#RunWith(PowerMockRunner.class)
#PrepareForTest()
public class ExampleTest {
#Mock
private ConnectionPool connectionPool;
#Mock
private Properties properties;
#Mock
private Service service = new Service(
connectionPool, properties, 1, 1);
#Mock
private Connection connection;
#Mock
private Statement statement;
#Mock
private ResultSet resultSet;
#InjectMocks
private Example example = new Example(
1, 1, connectionPool, properties);
#Test
public void testCall() throws Exception {
List<String> listInput= new ArrayList<>();
listInput.add("data1");
when(service.getMethod(listInput)).thenReturn(listInput);
example.call();
}
Question: How to mock Service class and its method, getMethod, call ?
Explanation: The Service class has method getMethod, which is interacting with the DB. So, as I am not able to mock this method, the code goes through and then I have to mock all the objects in the getMethod as connection, resultset etc. else it throws NullPointerException.
Please help me understand what I am doing wrong and if possible provide your guidance on the way I should approach the JUNITS for this kind of method call.
Mockito won't help you to mock an object if you have calling of new Service inside of your method.
Instead you need to use PowerMock.expectNew
Service mockService = PowerMock.createMock(Service.class);
PowerMock.expectNew(Service.class, connectionPool, properties, 1, 1)
.andReturn(mockService);
PowerMock.replay(mockService);
For PowerMockito there is an equivalent:
PowerMockito.whenNew(Service.class)
.withArguments(connectionPool, properties, 1, 1)
.thenReturn(mockService);
Please check this article.