3

This is my java thread run method and i want to write unit test for this method. But with infinte loop i can not do it. It would be nice anyone can help me with this.

 public void run() { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); String line = null; boolean oneTime = true; loadDescription(); while (true) { try { if (oneTime) { System.out.println("press enter to get the console..............."); oneTime = false; } line = in.readLine(); if (line != null) { processInput(line); } } catch (Exception e) { logger.error("Error occurred while processing console"); logger.error(e.getMessage(), e); } } } 

this is loadDescription() method

private void loadDescription() { BufferedReader in = null; StringBuffer stringBuffer = null; String str = null; try { stringBuffer = new StringBuffer(); in = new BufferedReader(new FileReader(IConstants.MANUAL_FILE)); str = in.readLine(); while (str != null) { stringBuffer.append(str + "\n"); str = in.readLine(); } dfixDescription = stringBuffer.toString(); } catch (Exception e) { logger.error(e.getMessage(), e); //To change body of catch statement use File | Settings | File Templates. } finally { try { if (in != null) { in.close(); } } catch (IOException e) { logger.error(e.getMessage(), e); //To change body of catch statement use File | Settings | File Templates. } } } 

and

private void processInput(String line) { line = line.trim(); logger.info("Admin Message received: " + line); if ("?".equalsIgnoreCase(line) || "".equals(line)) { printDescription(); } else if (line.toUpperCase().startsWith(AdminCommands.RELOAD)) { loadDescription(); printDescription(); } else if (line.toUpperCase().startsWith(AdminCommands.EXIT)) { adminManager.stopDFIXRouter(); logger.debug("Closing Application....."); logger.debug("Closed."); System.exit(0); } else if (line.toUpperCase().startsWith(AdminCommands.RESET_OUT_SEQUENCE)) { try { String sessionIdentifier = line.split(",")[1].trim(); int seqNo = Integer.parseInt((line.split(",")[2]).trim()); adminManager.resetOutSequence(sessionIdentifier, seqNo); } catch (Exception e) { logger.error(e.getMessage(), e); //To change body of catch statement use File | Settings | File Templates. } } else if (line.toUpperCase().startsWith(AdminCommands.RESET_IN_SEQUENCE)) { try { String sessionIdentifier = line.split(",")[1].trim(); int seqNo = Integer.parseInt((line.split(",")[2]).trim()); adminManager.resetInSequence(sessionIdentifier, seqNo); } catch (Exception e) { logger.error(e.getMessage(), e); //To change body of catch statement use File | Settings | File Templates. } } else if (line.toUpperCase().startsWith(AdminCommands.CONNECT)) { String sessionIdentifier = line.split(",")[1].trim(); adminManager.connectSession(sessionIdentifier); } else if (line.toUpperCase().startsWith(AdminCommands.DISCONNECT)) { String sessionIdentifier = line.split(",")[1].trim(); adminManager.disconnectSession(sessionIdentifier); } else if (line.toUpperCase().startsWith(AdminCommands.ACTIVATE)) { adminManager.startDFIXRouter(); } else if (line.toUpperCase().startsWith(AdminCommands.PASSIVATE)) { adminManager.stopDFIXRouter(); } else if (line.toUpperCase().startsWith(AdminCommands.RUN_EOD)) { try { String sessionIdentifier = line.split(",")[1].trim(); adminManager.runEod(sessionIdentifier); } catch (Exception e) { logger.error(e.getMessage(), e); //To change body of catch statement use File | Settings | File Templates. } } else if (line.toUpperCase().startsWith(AdminCommands.SHOW_STATUS)) { adminManager.showStatus(); } else { System.out.println("Usage: type ? for help"); } System.out.print(">"); } 

and these are related methods for run method. following is my test method

 @Test public void run_activate() throws Exception{ String data = "activate"; InputStream in = new ByteArrayInputStream(data.getBytes()); System.setIn(in); PowerMockito.mockStatic(AdminManager.class); PowerMockito.when(AdminManager.getInstance()).thenReturn(adminManagerTest); Mockito.doNothing().when(adminManagerTest).startDFIXRouter(); dfixrtrAdminTest.run(); Mockito.verify(adminManagerTest, Mockito.times(1)).startDFIXRouter(); } 

what is wrong with this. When i run test method it will not stop and i can not verify that needed methods are invoked how to handle this.

8
  • Also "But with infinte loop i can not do it." is a little vague. What specifically do you need help with? Commented Sep 27, 2017 at 11:11
  • One more problem of your code is that it asks for user input. Commented Sep 27, 2017 at 11:14
  • Then now is the time to refactor your code into dependency-injectable and unit-testable components. Currently it is not. Commented Sep 27, 2017 at 11:18
  • You missed that minimal part. Putting up so much code wont cut it either. And as said: your production code contains a bug - you do NOT want to loop infinite. And yes - you can't test code that would loop forever. But then you look into my answer and re-think what you are doing. Commented Sep 27, 2017 at 11:28
  • So in case your question gets deleted on you, and you decide to try again: focus on what you think your code should be doing. What it is doing right now is not making much sense. Commented Sep 27, 2017 at 11:28

4 Answers 4

17

You need to replace the code inside the infinite loop with a function.

You then write a unit test for that function.

Sign up to request clarification or add additional context in comments.

Comments

3

Obviously you can't test if a loop is really "infinite".

But then you can still step back and look at all the details this method is doing, like:

  • opening a reader from which it will read
  • having that special condition that ensures that "something" happens only once

In other words: as usually with unit tests, you carefully think about the different paths that your code can take (think: "white box testing"). That can tell you about test cases required to hit corner cases. On the other hand, you should also look at the public contract of your method (black box testing) - what are the things that you expect this method to do, without knowing about its implementation. That is how you think about your code, in order to then come up with reasonable tests.

And beyond that: your example is bogus. There shouldn't be an infinite loop here - at some point all lines will be read, and read() will not return anything else but null.

1 Comment

I posted all my code and having problem with while loop.
1

[Late Answer] @IsharaD the answer of @GhostCat is good. I also faced this issue and the best way to resolve it, is to separate the execution of your logic from the thread execution. The Runnable class is like a wrapper where you delegate the execution of your own method. Also, it will help you make your test very easy.

You should have something like this:

Your class:

public class YourClass { public void execute() { ... } } 

Your runnable:

public class YourClassTask implements Runnable { private YourClass yourClass; public YourClassTask(YourClass yourClass) { this.yourClass = yourClass; } @Override public void run() { yourClass.execute(); } } 

Comments

0

You can use do-while loop and a public variable which is set to true.

for unit test set variable to false

do while executes only once when contidion is false

1 Comment

Maybe you can edit your answer and post some code that demonstrates what you are describing?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.