Unable to mock accountStatus with Mockito - java

From below piece of code I am not able to mock checkAccountStatus and its coming as null. What changes do I need to do to resolve this issue?
Class
public AccessIDSearchResponse searchAccessID(AccessIDSearchRequest accessIDRequest) {
String[] productTypes = accessIDRequest.getProductTypes();
AccountResponse actResponse = checkAccountStatus(accessIDRequest);
System.out.println("Response is---->"+JsonService.getJsonFromObject(actResponse));
if (accessIDRequest.getSearchtype().equalsIgnoreCase("accountId") && !Utility.isEmpty(actResponse)
&& !"FREEVIEW".equalsIgnoreCase(actResponse.getAccountStatus())) {
errorHandler.error(ErrorMessages.EPO_EXISTINGTV_ERR_07, ErrorMessages.ACCESS_ID_NOT_FOUND);
}
}
public AccountResponse checkAccountStatus(AccessIDSearchRequest request) {
AccessIDSearchResponse response = new AccessIDSearchResponse();
SearchAccessIdContent content = new SearchAccessIdContent();
DTVNAccountDetails accountDetails = new DTVNAccountDetails();
accountDetails.setAccountNumber(request.getSearchvalue());
List<DTVNAccountDetails> list = new ArrayList<>();
list.add(accountDetails);
content.setDtvAccountList(list);
response.setContent(content);
return helper.getAccountStatus(response);
}
Helper
public AccountResponse getAccountStatus(AccessIDSearchResponse accessIDResponse) {
AccountResponse accountResponse = null;
AccountRequest request = new AccountRequest();
Account account = new Account();
account.setCustomerID(accessIDResponse.getContent().getDtvAccountList().get(0).getAccountNumber());
request.setAccount(account);
String response = dtvnClients.callandGetDtvnStatus(request);
System.out.println("Response is--->"+response);
if (!Utility.isEmpty(response)) {
accountResponse = JqUtil.runJqQueryAndGetString(".content.accountResponse", response,
AccountResponse.class);
if (!Utility.isEmpty(accountResponse) && accountResponse.isSubscribable()
&& !Utility.isEmpty(accountResponse.getAccountStatus())
&& accountResponse.getAccountStatus().equalsIgnoreCase("FREEVIEW")) {
return accountResponse;
}
}
return accountResponse;
}
Test Class
#Test(expected = ServiceException.class)
public void test_searchAccessID_3_sample() throws Exception {
AccessIDSearchRequest request = new AccessIDSearchRequest();
CommonData commonData = new CommonData();
commonData.setAppName("IDSE");
commonData.setLoginId("qay_slid_sr1281");
request.setCommonData(commonData);
request.setSearchtype("accountId");
request.setSearchvalue("qay_slid_sr1281");
request.setMode("abc");
SearchAccessIdContent content = new SearchAccessIdContent();
AccountResponse accountResponse = new AccountResponse();
accountResponse.setAccountStatus("Sucess");
accountResponse.setSubscribable(true);
Mockito.when(helper.getAccountStatus(accessIDResponse)).thenReturn(accountResponse);
Mockito.when(service.checkAccountStatus(request)).thenReturn(accountResponse);
service.searchAccessID(header, request);
}

Your mocks are not properly configured.
When you call
service.searchAccessID(header, request);
it was make the underlying call
checkAccountStatus(request);
(which is correctly mocked and returns accountResponse), but this one does instanciate its result object, so your first mock will never be triggered.
Updating your first mock to something more permissive will probably fix your problem
Mockito.when(helper.getAccountStatus(any(AccessIDSearchResponse.class))).thenReturn(accountResponse);
To be honest, your code is hardly testable because you instanciate too many objects everywhere. Going for mocks here will be a pain in the future when you refactor something. If I were you I would rewrite this piece of code using a TDD approach and favorizing more testable patterns.

Related

How to mock KafkaAdminClient

I am trying to do a unit test for the code below. I am able to test the exception block but unable to test the below block as I am getting an exception.
How can I mock or set values to the ListTopicsResult topics = client.listTopics(), so that the flow goes into the if block?
if(!topics.names.get().isEmpty()) { response = true; }
public boolean isBrokerRunning() {
boolean response = false;
Properties property = new Properties();
try(AdminClient client = KafkaAdminClient.create(property)) {
ListTopicsResult topics = client.listTopics();
if(!topics.names.get().isEmpty()) {
response = true;
}
} catch(Exception ex) {
response = false;
}
}
KafkaAdminClient.create
This is a static function call, so you need to mock static function, You can use powermockit on top of mockito to mock static functions.
see this example
use mockito-inline can do this. need some trick
#Test
public void mockCreateAdmin() {
AdminClient mock = mock(KafkaAdminClient.class);
try (MockedStatic<Admin> staticMock = mockStatic(Admin.class)) {
staticMock.when(() -> Admin.create(any(Properties.class))).thenReturn(mock);
KafkaAdminClient adminClient = (KafkaAdminClient) KafkaAdminClient.create(new Properties());
// when
// then
assertEquals(mock, adminClient);
}
}

How get results of test in a Dynamic Test in Junit5?

my function is similar to:
#TestFactory
public Stream<DynamicTest> dynamicTest() throws Exception {
String geocodingAnasJsonTest = properties.getProperty("smart-road.simulator.json.geocoding-it.anas.testSuite.test");
String endpoint = properties.getProperty("smart-road.simulator.endpoint.anasGeocoding");
RequestSpecification request = RestAssured.given().header("Authorization", auth);
request.accept(ContentType.JSON);
request.contentType(ContentType.JSON);
JsonNode jsonObjectArray = JsonMappingUtil.getJsonFileFromPath(geocodingAnasJsonTest);
Stream<JsonNode> elementStream = StreamSupport.stream(Spliterators
.spliteratorUnknownSize(jsonObjectArray.elements(),
Spliterator.ORDERED), false);
return elementStream.map(jsonNode -> DynamicTest.dynamicTest(String.format("Test ID: %s", jsonNode.get("test_name")),
() -> {request.body(jsonNode.get("request").toString());
Response response = request.post(endpoint);
int statusCode = response.getStatusCode();
boolean res = false;
if (statusCode >= 200 && statusCode < 300) {
res = true;
}
try {
assertEquals(true, res, properties.getProperty("smart-road.response.smart-road.message.status.ok"));
logger.info(properties.getProperty("smart-road.response.smart-road.message.status.ok"));
String responseOK=jsonNode.get("response").toString();
assertEquals(responseOK, response.asString(), properties.getProperty("smart-road.response.smart-road.message.status.right-end"));
logger.info(properties.getProperty("smart-road.response.smart-road.message.status.right-end"));
} catch (AssertionFailedError er) {
logger.error(properties.getProperty("smart-road.response.smart-road.message.status.assertion-failed"));
fail("Test Fallito");
Assertions.assertTrue(true);
}
}
)//fine dynamicTest
);//fine map
}//fine metodo
I have 20 children test.
I run test in main:
SummaryGeneratingListener listener = new SummaryGeneratingListener();
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectMethod(Test.class,"dynamicTest"))
.build();
Launcher launcher = LauncherFactory.create();
launcher.registerTestExecutionListeners(listener);
launcher.execute(request);
Now with summary= listener.getSummary() i dont read all tests result but only count Failed or Successfull test.
How i read all result fail/success for all tests?
I will want a map like this:
TEST_ID - RESULTS
test0001 Success
test0002 Fail
test0003 Success
test0004 Success
test0005 Fail
How i get this? Is possible?
Thanks
Regards
One approach is to create your own implementation of org.junit.platform.launcher.TestExecutionListener and register it with the launcher. You may look at the source code of SummaryGeneratingListener as a first start. You could change executionFinished(..) to build up the map of test results. Here's a sketch:
class MySummaryListener implements TestExecutionListener {
private Map<String, TestExecutionResult.Status> summary = new HashMap<>();
#Override
public void executionFinished(TestIdentifier testIdentifier, TestExecutionResult testExecutionResult) {
summary.put(testIdentifier.getDisplayName(), testExecutionResult.getStatus());
}
}
There's probably more you want to do in the listener but it should give you an idea where to start.

is it possible to return "if condition satisfies return a list else return an error message" using a java method

I know that in Java a method can return only one return type... But if there is any possiblity to this, kindly let me know. From the below method I am trying to return a list if condition satisfies else i am trying to return an error message.
Here is my code:
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return "Incorrect loginId..Please enter valid loginId";
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return companyList;
} else {
return "You are not Authorized";
}
} else {
return "Incorrect Password";
}
Yes its possible, create a custom Exception say 'MyAppException' and throw that exception with the error message you want.
Write your logic in a try{}catch block and throw the exception in catch so that the response has the error message
public List<CompanyMaster> getCompanies(#RequestBody UserDetails user) throws MyAppppException
{
try
{
//your logic which throws error
return companyList;
}
catch( final MyAppException we )
{
throw new MyAppException("User not found", HttpStatus.NOT_FOUND);
}
}
Refer this link
https://www.codejava.net/java-core/exception/how-to-create-custom-exceptions-in-java
You can achieve this by creating a new presenter Class which contains List and status of type String and change the return type of getCompanies method to presenter class like
public CompaniesPresenter getCompanies()
And your CompaniesPresenter class should look like
public class CompaniesPresenter {
private List<CompanyMaster> companyMaster;
private string status;
//default constructor
public CompaniesPresenter(){
}
//parameterized constructor to return only string in exception case
public CompaniesPresenter(Stirng status){
this.status = status;
}
//parametirized constructor to return success case
public CompaniesPresenter(List<CompanyMaster> companyMaster, Stirng status){
this.companyMaster = companyMaster;
this.status = status;
}
//getters and setters
}
This is how your updated method lokks like
#RequestMapping(value = "/getcompanies", method = RequestMethod.POST)
public CompaniesPresenter getCompanies(#RequestBody UserDetails user) {
String OrgLoginId = user.getOrgLoginId();
String password = user.getuPassword();
String checkLoginId = null;
String uPassword = null;
String encPassword = null;
String loginId = null;
String checkAuthorized = null;
// String loginId=userService.getLoginId(OrgLoginId);
List<Object[]> CheckIdPassword = userService.checkLoginId(OrgLoginId);
List<Object[]> results = CheckIdPassword;
for (Object[] obj : results) {
checkLoginId = obj[0].toString();
if (null == obj[1]) {
uPassword = "";
} else {
uPassword = obj[1].toString();
}
loginId = obj[2].toString();
}
checkAuthorized = loginId.substring(0, 3);
if (null != password) {
MD5 md5 = new MD5();
encPassword = md5.getPassword(password);
}
if (checkLoginId == null) {
return new CompaniesPresenter("Incorrect loginId..Please enter valid loginId");
} else if (encPassword.equals(uPassword)) {
if (checkAuthorized.equals("STE")) {
List<CompanyMaster> companyList = userService.getCompanyList(OrgLoginId);
return new CompaniesPresenter(companyList,"success");
} else {
return new CompaniesPresenter("You are not Authorized");
}
} else {
return new CompaniesPresenter("Incorrect Password");
}
This is not tested please make sure for any compilation errors
vavr's Either class would be a good choice.
The usage of custom exception is most reasonable solution. However, creating custom exception for just one case is not ideal always.
Another solution is to return empty List from your method, check if the List is empty in your servlet (or wherever you are invoking this method from), and show error message there.
It seems like you want to return multiple error messages for different cases. In this case, custom exception is recommended solution. If you don't like custom exceptions, you can return List<Object> and populate error message as the first element in the list. In the place where this List is obtained, check if the first element is instanceOf String or CompanyMaster. Based on what it is, you can perform your operations. This is a weird but possible solution (only if you don't like custom exceptions).
You need to understand the problem first. You are mixing two things here, first authorization, does the user has correct privileges to get company details, second giving the company details itself. Let's understand the first problem when a user tries to access "/getcompanies" endpoint will you let him in if does not have access, in REST world your security model should take care of it. I would use spring security to achieve this. My recommendation would be to explore on "interceptor" and solve the problem of invalid user. This will make your other problem easy as your "/getcompanies" endpoint can focus only on getting the details and return it (SRP).

Mock InfluxDB client to test a MetricCollector class

I have a metrics collector that store data on InfluxDB, I want to test the methods to store that metrics. I'm trying it but I'm not able to mock the InfluxDB client. I don't want to point to a real InfluxDB on the test environment.
Everything I've achieved so far are some "null pointer exceptions" and conection refused.
This is my test (using TestNG). What am I doing wrong?
#Test
public void validateMetrics() {
String influxHost = "http://localhost";
String credentials = "admin:admin";
String influxDatabaseName = "testDataBase";
influxDB = InfluxDBFactory.connect(influxHost, credentials.split(":")[0], credentials.split(":")[1]);
MetricsCollector metricsCollector = null;
try {
String hostName = "test-server-01";
int statusValue = 1;
metricsCollector = new MetricsCollector(influxDB);
BatchPoints metrics = metricsCollector.initBatchPoint(influxDatabaseName);
Point point = metricsCollector.setMetric(hostName, "status", statusValue);
metrics = metricsCollector.addToMetrics(metrics, point);
Assert.assertTrue(metrics.getPoints().get(0).lineProtocol().contains(hostName));
Assert.assertTrue(metrics.getPoints().get(0).lineProtocol().contains("status=" + statusValue));
} finally {
if (metricsCollector != null) {
metricsCollector.closeConnection();
}
}
}
I suspect the reason you cannot mock the InfluxDB client is that it is created by a static method: InfluxDBFactory.connect(). To mock this you will need PowerMock.
Something like this:
#PrepareForTest({InfluxDBFactory.class})
public class ATestClass {
#Test
public void validateMetrics() {
// this allows you to mock static methods on InfluxDBFactory
PowerMockito.mockStatic(InfluxDBFactory.class);
String influxHost = "http://localhost";
String credentials = "admin:admin";
String influxDatabaseName = "testDataBase";
InfluxDB influxDB = Mockito.mock(InfluxDB.class);
// when the connect() method is invoked in your test run it will return a mocked InfluxDB rather than a _real_ InfluxDB
PowerMockito.when(InfluxDBFactory.connect(influxHost, credentials.split(":")[0], credentials.split(":")[1])).thenReturn(influxDB);
// you won't do this in your test, I've only included it here to show you that InfluxDBFactory.connect() returns the mocked instance of InfluxDB
InfluxDB actual = InfluxDBFactory.connect(influxHost, credentials.split(":")[0], credentials.split(":")[1]);
Assert.assertSame(influxDB, actual);
// the rest of your test
// ...
}
}
Note: there are specific compatability requirements for TestNG, Mockito and PowerMock described here and here.
I totally misunderstanding how mockito works. Here is my fixed code:
#Mock private InfluxDB influxDB;
#Test
public void validateMetrics() {
MetricsCollector metricsCollector = null;
String influxHost = "http://localhost";
String credentials = "admin:admin";
String influxDatabaseName = "testDataBase";
influxDB = InfluxDBFactory.connect(influxHost, credentials.split(":")[0], credentials.split(":")[1]);
try {
String hostName = "test-server-01";
int statusValue = 1;
metricsCollector = new MetricsCollector(influxDB);
BatchPoints metrics = metricsCollector.initBatchPoint(influxDatabaseName);
Point point = metricsCollector.setMetric(hostName, "status", statusValue);
metrics = metricsCollector.addToMetrics(metrics, point);
Assert.assertTrue(metrics.getPoints().get(0).lineProtocol().contains(hostName));
Assert.assertTrue(metrics.getPoints().get(0).lineProtocol().contains("status=" + statusValue));
} finally {
if (metricsCollector != null) {
metricsCollector.closeConnection();
}
}
}
Yep, added that simple "mock" annotation and all works fine.

Wanted but not invoke: Mockito PrintWriter

Hi I am working on a project and using PrintWriter class for opening and writing in the file. But when I am writing the test case for same it gives following error at Line 153
Wanted but not invoked:
mockPrintWriter.println("ID url1
");
-> at x.y.z.verify(ProcessImageDataTest.java:153)
Actually, there were zero interactions with this mock.
Code: (Uses Lombok Library)
ProcessImageData.java
#Setter
#RequiredArgsConstructor
public class ProcessImageData implements T {
private final File newImageDataTextFile;
#Override
public void execute() {
LineIterator inputFileIterator = null;
try {
File filteredImageDataTextFile = new File(filteredImageDataTextFilepath);
PrintWriter writer = new PrintWriter(newImageDataTextFile);
inputFileIterator = FileUtils.lineIterator(filteredImageDataTextFile, StandardCharsets.UTF_8.displayName());
while (inputFileIterator.hasNext()) {
if(someCondition)
**Line51** writer.println(imageDataFileLine);
//FileUtils.writeStringToFile(newImageDataTextFile, imageDataFileLine + NEWLINE, true);
}
}
} catch (Exception e) {
} finally {
LineIterator.closeQuietly(inputFileIterator);
**LINE63** writer.close();
}
}
ProcessImageDataTest.java
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ProcessImageData.class, FileUtils.class, Printwriter.class })
public class ProcessImageDataTest {
private ProcessImageData processImageData;
private static final String FILTERED_IMAGE_DATA_TEXT_FILE_PATH = "filteredFilepath";
private File FILTEREDFILE = new File(FILTERED_PATH);
private static final File IMAGE__FILE = new File("imageFilePath");
private LineIterator lineIterator;
#Mock
private PrintWriter mockPrintWriter;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
processImageData = new ProcessImageData(Palettes_file, FILTERED_PATH, IMAGE_FILE);
PowerMockito.mockStatic(FileUtils.class);
PowerMockito.whenNew(PrintWriter.class).withArguments(IMAGE_FILE).thenReturn(mockPrintWriter);
PowerMockito.when(FileUtils.lineIterator(FILTERED_FILE, StandardCharsets.UTF_8.displayName())).thenReturn(lineIterator);
PowerMockito.when(lineIterator.hasNext()).thenReturn(true, true, false);
}
#Test
public void testTaskWhenIDInDBAndStale() throws IOException {
PowerMockito.when(lineIterator.nextLine()).thenReturn(ID2 + SPACE + URL1, ID1 + SPACE + URL2);
processImageData.execute();
List<String> exepctedFileContentOutput = Arrays.asList(ID2 + SPACE + URL1 + NEWLINE);
verify(exepctedFileContentOutput, 1, 1);
}
#Test
public void testTaskWhenIDNotInDB() throws IOException {
PowerMockito.when(lineIterator.nextLine()).thenReturn(ID2 + SPACE + URL1, ID3 + SPACE + URL2);
processImageData.execute();
List<String> exepctedFileContentOutput = Arrays.asList(ID3 + SPACE + URL2 + NEWLINE);
verify(exepctedFileContentOutput, 1, 1);
}
private void verify(List<String> exepctedFileContentOutput, int fileWriteTimes, int fileReadTimes) throws IOException {
for (String line : exepctedFileContentOutput){
**Line153** Mockito.verify(mockPrintWriter, Mockito.times(fileWriteTimes)).print(line);
}
PowerMockito.verifyStatic(Mockito.times(fileReadTimes));
FileUtils.lineIterator(FILTERED_IMAGE_DATA_TEXT_FILE, StandardCharsets.UTF_8.displayName());
}
}
I am mocking a new operator for PrintWriter also, injecting using beans. What is the mistake I am doing?? I am stuck on it from long time and not getting the error?
Any help is appreciated.
Updated :
I did changes suggested below and updated the code, but now I get the error:
Wanted but not invoked: mockPrintWriter.print("ASIN2 url1 "); ->
at softlines.ctl.ruleExecutor.tasks.ProcessImageDataTest.verify‌​(ProcessImageDataTes‌​t.java:153)
However, there were other interactions with this mock: -> at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​51) ->
at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​51) ->
at softlines.ctl.ruleExecutor.tasks.ProcessImageData.execute(Pr‌​ocessImageData.java:‌​58) –
I see 3 issues in your test:
You don't try to mock the correct constructor, indeed in the method execute, you create your PrintWriter with only one argument of type File while you try to mock the constructor with 2 arguments one of type File and the other one of type String.
So the code should rather be:
PowerMockito.whenNew(PrintWriter.class)
.withArguments(IMAGE_FILE)
.thenReturn(mockPrintWriter);
To be able to mock a constructor you need to prepare the class creating the instance which is ProcessImageData in this case, so you need to add ProcessImageData.class in the annotation #PrepareForTest. (I'm not sure ProcessImageDataTest.class is needed there)
The field lineIterator should be annotated with #Mock.
Instead of verifying print with a new line, you should verify directly println without new line it is much less error prone.
I simplified your code to show the idea.
Assuming that ProcessImageData is:
public class ProcessImageData {
private final File newImageDataTextFile;
public ProcessImageData(final File newImageDataTextFile) {
this.newImageDataTextFile = newImageDataTextFile;
}
public void execute() throws Exception{
try (PrintWriter writer = new PrintWriter(newImageDataTextFile)) {
LineIterator inputFileIterator = FileUtils.lineIterator(
newImageDataTextFile, StandardCharsets.UTF_8.displayName()
);
while (inputFileIterator.hasNext()) {
writer.println(inputFileIterator.nextLine());
}
}
}
}
My unit test would then be:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ProcessImageData.class, FileUtils.class})
public class ProcessImageDataTest {
private File file = new File("imageFilePath");
private ProcessImageData processImageData;
#Mock
private PrintWriter mockPrintWriter;
#Mock
private LineIterator lineIterator;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
processImageData = new ProcessImageData(file);
PowerMockito.whenNew(PrintWriter.class)
.withArguments(file)
.thenReturn(mockPrintWriter);
PowerMockito.mockStatic(FileUtils.class);
PowerMockito.when(
FileUtils.lineIterator(file, StandardCharsets.UTF_8.displayName())
).thenReturn(lineIterator);
PowerMockito.when(lineIterator.hasNext()).thenReturn(true, true, false);
}
#Test
public void testExecute() throws Exception {
PowerMockito.when(lineIterator.nextLine()).thenReturn("Foo", "Bar");
processImageData.execute();
Mockito.verify(mockPrintWriter, Mockito.times(1)).println("Foo");
Mockito.verify(mockPrintWriter, Mockito.times(1)).println("Bar");
}
}
For more details please refer to How to mock construction of new objects.
how can I add verification in unit test for writer.close?
One way could be to simply check that close() at be called once by adding the next line to your unit test:
Mockito.verify(mockPrintWriter, Mockito.times(1)).close();
Your construction of the PrintWriter doesn't match the mock. You told PowerMockito to return your mock like this:
PowerMockito.whenNew(PrintWriter.class).withArguments(IMAGE_FILE , StandardCharsets.UTF_8.name()).thenReturn(mockPrintWriter);
So you would have to say:
new PrintWriter(IMAGE_FILE, "UTF-8"); // 2 arguments
But instead in your execute method in the code that is being tested, you do:
PrintWriter writer = new PrintWriter(newImageDataTextFile); // only 1 argument
So you either need to change the PowerMockito withArguments clause, or you need to add "UTF-8" to the constructor invocation in the execute method.

Categories