PowerkMock-ing BufferedReader runs interminately - java

What I want to do is to mock newly created instance of BufferedReader. Here's the code that should be tested:
A.java
...
#Override
public String read(String fileName) throws IOException {
...
try {
fileReader = new FileReader(fileName);
bufferedReader = new BufferedReader(fileReader);
String tmp;
StringBuilder builder = new StringBuilder();
while ((tmp = bufferedReader.readLine()) != null) {
builder.append(tmp);
}
return builder.toString();
} catch (IOException e) {
...
} finally {
...
}
}
...
What I have to do, is to PowerMock both FileReader creation and BufferedReader creation.
ATest.java
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
public class ATest {
#Mock
private FileReader fileReader;
#Mock
private BufferedReader bufferedReader;
...
#Test
public void test() throws Exception {
PowerMockito.whenNew(FileReader.class).withArguments(FILE_NAME).thenReturn(fileReader);
PowerMockito.whenNew(BufferedReader.class).withAnyArguments().thenReturn(bufferedReader);
PowerMockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Throwable {
return "test";
}
}).when(bufferedReader).readLine();
assertArrayEquals(reader.read(FILE_NAME), new String[]{"test"});
}
}
But then the test never terminates. I can't even debug it.
As soon as PowerMockito.doAnswer() is removed the code is executed (and is available for debugging). I've also tried to use Mockito.mock() instead of PowerMockito.doAnswer(), it doesn't help.
What may cause interminate execution of the test?

Just a different perspective: one could say that your real problem in your code are those two calls to new() for FileReader / BufferedReader.
What if you passed a Reader to this method; instead of a String denoting a file name?
What if you passed a "ReaderFactory" to the underlying class that contains this method read(String)? (where you would be using dependency injection to get that factory into your class)
Then: you would be looking at an improved design - and you would not need to use PowerMock. You could step back and go with Mockito or EasyMock; as there would be no more need to mock calls to new.
So, my answer is: you created hard-to-test code. Now you try to fix a design problem using the big (ugly) PowerMock hammer. Yes, that will work. But it is just the second best alternative.
The more reasonable option is to learn how to write testable code (start here for example); and well, write testable code. And stop using PowerMock ( I have done that many months back; after a lot of PowerMock-induced pain; and I have never ever regretted this decision ).

The problem was, that I also had to mock value after first bufferedReader.readLine(), because otherwise it would always return the mocked value, thus not terminating.
Mockito.when(bufferedReader.readLine()).thenReturn("first line").thenReturn(null);
NOTE
Though this is the actual answer to the question, but you should strongly consider choosing the design GhostCat has suggested in another answer (which I eventually did).

Related

Variable outside the loop marked as 'DU'-anomaly in PMD

I get a lot of this anomaly. Here BufferedData ist marked as DU' anomaly by PMD. What is wrong with this approach?
private static void summUpBuffer(BufferedReader in) throws IOException {
List<String> bufferedData = new ArrayList<>();
for (String line = in.readLine(); line != null; line = in.readLine()) {
bufferedData.add(line);
}
}
'DU Anomaly' means the code might not do what you intended. Since you never use the variable bufferedData, it is flagged up due to being a pointless assignment.
In essense your method doesn't do anything. All its side effects are local and will be forgotten as soon as the method returns.
Complete the method and the warning will most likely go away.
Edit: Actually there is one side-effect, namely the reading of the BufferedReader. That's probably why bufferedData is the only thing flagged in this way.

Unit tests for file parsing and translation

How do I write the unit test for the following method - so that it is input file agnostic?
It seems that the reading and translation into business objects are distinct responsibilities - which need to be separate.
That would allow the business translation to be testable.
Any suggestions are welcome.
public Map<header,record> createTradeFeedRecords(String tradeFile,String config) throws Exception {
Map<header,record> feedRecordMap =
new LinkedHashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(tradeFile))) {
for (String line; (line = reader.readLine()) != null;) {
if (line.trim().isEmpty() || line.startsWith("#") )
continue;
Record record = recordParser.extractTradeFeedRecord(line,config):
feedRecordMap .put(record.getHeader(), record) ;
}
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
}
return feedRecordMap ;
}
You could use JUnit's TemporaryFolder rule (or, if using JUnit5, its equivalent extension) to create an input file for your test(s). You would then provide the path to this file in your tradeFile argument and your test would operate on the file you created. On completion of the test JUnit will discard the temporary folder, thereby adhering to the test principle of self containment.
This is, I think, the approach which most closely mirrors the actual behaviour of the createTradeFeedRecords method.
However, if you really don't want to play around with the file system in your tests or indeed if you just want to achieve this ..
It seems that the reading and translation into business objects are distinct responsibilities - which need to be separate.
... then you could extract the new FileReader(tradeFile) call behind an interface. Something like this, perhaps:
public interface TradeReader {
Reader read(String input);
}
The 'normal' implementation of this would be:
public class FileTradeReader implements TradeReader {
#Override
public Reader read(String input) {
return new FileReader(input);
}
}
You could then provide an implementation of this for use in your test case:
public class StubTradeReader implements TradeReader {
#Override
public Reader read(String input) {
return new StringReader(input);
}
}
In your tests you would then inject the class-under-test (i.e. the class which contains createTradeFeedRecords) with an instance of StubTradeReader. In this way, the createTradeFeedRecords method invoked within your tests would act upon whatever input you provided when creating the StubTradeReader and your tests would have no interaction with the file system.
You could also test the TradeReader separately (using the temporary folder approach outlined above, perhaps) thereby achieving the goal of separating reading and translating and testing both independently.

Read methods from a text file and execute them in the program

I have a text file and that file lists all the operations that can be performed on a Pump Class.
example of the content of text file
Start PayCredit Reject Start PayCredit Reject TurnOff
....
.... so on.
These are the methods of the Pump class(Start(), Reject() etc)
I need to write a code where I can Read these method from the file one by one and execute them.
public static void main(String[] args) throws IOException
{
Pump gp= new Pump();
File file=new File("C:\\Users\\Desktop\\checker\\check.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line=null;
while((line=br.readLine())!=null)
{
String words[]=line.split(" ");
for(int i=0;i<words.length;i++)
{
String temp=words[i]+"()";
gp.temp; //compilation error
}
}
}
Could you tell me how can I achieve this functionality.
If you're not so familiar with reflection, maybe try using org.springframework.util.ReflectionUtils from the Spring Framework project?
The code would go something like this:
Pump gp = new Pump();
....
String temp = // from text file
....
Method m = ReflectionUtils.findMethod(Pump.class, temp);
Object result = ReflectionUtils.invokeMethod(m, gp);
You would need to use reflection to invoke the methods at runtime. Here is a simple example that assumes that all methods do not take any parameters.
Class<? extends Pump> pumpClass = gp.getClass();
String methodName = words[i];
Method toInvoke = pumpClass.getMethod(methodName);
if (null != toInvoke) {
toInvoke.invoke(gp);
}
First of all be aware that Java is not interpreted at runtime. So you can't do it this way.
If you already have the methods such as Start PayCredit Reject TurnOff and so on you can do it in the following way:
for(int i=0;i<words.length;i++)
{
String temp=words[i];
if (temp.equals("Start") gp.Start();
else if (temp.equals("PayCredit") gp.PayCredit();
...
}
use a switch case
for(int i=0;i<words.length;i++) {
String temp=words[i];
switch(temp) {
case "Start":
gp.start();
break;
case "PayCredit":
gp.PayCredit();
break;
}
}
You can use reflection to do this, e.g.
String line=null;
Method method = null;
while((line=br.readLine())!=null)
{
String words[]=line.split(" ");
for(int i=0;i<words.length;i++)
{
String temp=words[i];
method = getClass().getMethod(temp);
method.invoke(this);
}
}
That's assuming you want to call the method on this, of course, and that it's an instance method. Look at Class.getMethod and related methods, along with Method itself, for more details. You may want getDeclaredMethod instead, and you may need to make it accessible.
I would see if you can think of a way of avoiding this if possible though - reflection tends to get messy quickly. It's worth taking a step back and considering if this is the best design. If you give us more details of the bigger picture, we may be able to suggest alternatives.

Constructor handling exception and using this keyword Java

I have two constructors for my class, one that takes File object and the other takes a String object, and I want to use the this keyword. The function with the implementation is the one with File as parameter, and the one with String will call this. Now I want to check for exception in the constructor that takes String but I get error, that this should be the first line. How can I check for errors then call this.
Here is my code:
public Test (String filename) {
if (filename == null)
throw new NullPointerException("The String you entered is null.");
if (filename.isEmpty())
throw new IllegalArgumentException("The String you entered is empty.");
this(new File(filename)); // error
}
public Test (File f) {
/* implementation here */
}
This is the exact error: Constructor call must be the first statement in a constructor
Unfortunately, this is impossible in Java thanks to their arbitrary restrictions. You have two main possibilities.
The more idiomatic Java technique is to wrap everything in a factory function so you can catch the exception. Factory functions are also useful because they let you create objects polymorphically, and help hide the details of what object is actually created.
public static Test create(String filename){
if (filename == null)
throw new NullPointerException("The String you entered is null.");
if (filename.isEmpty())
throw new IllegalArgumentException("The String you entered is empty.");
return new Test(filename);
}
private Test (String filename) {
this(new File(filename));
}
public Test (File f) {
/* implementation here */
}
The other option is to write the constructor in bytecode, where there are no such restrictions present. Unfortunately, bytecode is less readable and maintainable, so you'll probably want to minimize the amount of bytecode in a primarily Java app. You might also be able do this in a non Java language like AspectJ.
Edit: If you're not actually trying to catch the exceptions, then there's a third possibility. You can insert arbitrary code before the super constructor call by creating a separate function which performs the checks and then passing it as a dummy argument to the super constructor call. Since arguments are evaluated first, your code will run first, but this is a bit of a hack.
public Test (String filename) {
this(doChecks(filename), new File(filename));
}
private static Void doChecks(String filename){
if (filename == null)
throw new NullPointerException("The String you entered is null.");
if (filename.isEmpty())
throw new IllegalArgumentException("The String you entered is empty.");
return null;
}
public Test (Void dummy, File f) {
this(f);
}
public Test (File f) {
/* implementation here */
}
In case we use this or super in constructor, either this or super should be the first statement in the constructor. It is better, if you throw exception from a particular constructor.
public Test (String filename) {
this(new File(filename));
}
Let the second constructor handle any exception, caused by passing null.
public Test (File file) {
// exception handling code
// or new instance creation
}
No, you cannot check for errors before call this. It's forbidden by the specification. In fact, you didn't need it. Let new File(filename) to throw exceptions.
edit: I saw aizen92's comment: Actually that is what my constructor with the implementation has, it catches the exception may be thrown by file, so I just add the null exception and use this directly in my second constructor?
public Test (String filename) {
this((filename == null || filename.isEmpty()) ? null : new File(filename));
}

Getting an InputStream to read more than once, regardless of markSupported()

I need to be able to re-use a java.io.InputStream multiple times, and I figured the following code would work, but it only works the first time.
Code
public class Clazz
{
private java.io.InputStream dbInputStream, firstDBInputStream;
private ArrayTable db;
public Clazz(java.io.InputStream defDB)
{
this.firstDBInputStream = defDB;
this.dbInputStream = defDB;
if (db == null)
throw new java.io.FileNotFoundException("Could not find the database at " + db);
if (dbInputStream.markSupported())
dbInputStream.mark(Integer.MAX_VALUE);
loadDatabaseToArrayTable();
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
if (dbInputStream.markSupported())
dbInputStream.reset();
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
String CSV = "";
for (int i = 0; fileScanner.hasNextLine(); i++)
CSV += fileScanner.nextLine() + "\n";
db = ArrayTable.createArrayTableFromCSV(CSV);
}
public void reloadDatabase()//A method called by the UI
{
try
{
loadDatabaseToArrayTable();
}
catch (Throwable t)
{
//Alert the user that an error has occurred
}
}
}
Note that ArrayTable is a class of mine, which uses arrays to give an interface for working with tables.
Question
In this program, the database is shown directly to the user immediately after the reloadDatabase() method is called, and so any solution involving saving the initial read to an object in memory is useless, as that will NOT refresh the data (think of it like a browser; when you press "Refresh", you want it to fetch the information again, not just display the information it fetched the first time). How can I read a java.io.InputStream more than once?
You can't necessarily read an InputStream more than once. Some implementations support it, some don't. What you are doing is checking the markSupported method, which is indeed an indicator if you can read the same stream twice, but then you are ignoring the result. You have to call that method to see if you can read the stream twice, and if you can't, make other arrangements.
Edit (in response to comment): When I wrote my answer, my "other arrangements" was to get a fresh InputStream. However, when I read in your comments to your question about what you want to do, I'm not sure it is possible. For the basics of the operation, you probably want RandomAccessFile (at least that would be my first guess, and if it worked, that would be the easiest) - however you will have file access issues. You have an application actively writing to a file, and another reading that file, you will have problems - exactly which problems will depend on the OS, so whatever solution would require more testing. I suggest a separate question on SO that hits on that point, and someone who has tried that out can perhaps give you more insight.
you never mark the stream to be reset
public Clazz(java.io.InputStream defDB)
{
firstDBInputStream = defDB.markSupported()?defDB:new BufferedInputStream(defDB);
//BufferedInputStream supports marking
firstDBInputStream.mark(500000);//avoid IOException on first reset
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
dbInputStream.reset();
dbInputStream.mark(500000);//or however long the data is
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
db = ArrayTable.createArrayTableFromCSV(CSV.toString());
}
however you could instead keep a copy of the original ArrayTable and copy that when you need to (or even the created string to rebuild it)
this code creates the string and caches it so you can safely discard the inputstreams and just use readCSV to build the ArrayTable
private String readCSV=null;
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
if(readCSV==null){
this.dbInputStream = firstDBInputStream;
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
readCSV=CSV.toString();
fileScanner.close();
}
db = ArrayTable.createArrayTableFromCSV(readCSV);
}
however if you want new information you'll need to create a new stream to read from again

Categories

Resources