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.