I am writing a JUnit for a method that uses FileInputStream and in the constructor only the file name is passed. The file is created as part of a servlet request and this file is not stored any where.
I am trying to Mock FileInputStream using PowerMockito so that it gives me a mocked file object. Unfortunately I get FileNotFoundException which is valid but I am not sure how to test this method then because the file doesn't exist.
Method under test:
public String viewReport() throws Exception {
this.inputStream = new FileInputStream(DOCUSIGN_REPORT_FILE);
try {
boolean returnReport = validateRequest();
if (returnReport) {
intgList = this.generateViewIntegrationReportData(getESignUIConfig());
this.createCSVFile(intgList, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return null;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return null;
}
return UiIntegrationKeyConstants.REPORT_REPSONSE;
}
JUnit test so far.
#Test
public void testViewReport() throws Exception {
Map<String, Object> actionMap = new HashMap<>();
actionMap.put("application", "ESignatureIntegrationAction");
ActionContext.setContext(new ActionContext(actionMap));
FileInputStream inputStream = Mockito.mock(FileInputStream.class);
PowerMockito.whenNew(FileInputStream.class).withAnyArguments().thenReturn(inputStream);
action = new ESignatureIntegrationAction();
action.viewReport();
}
I get an exception when the code reaches to new FileInputStream(DOCUSIGN_REPORT_FILE);
Thanks for the help.
I would suggest to refactor your code in a way that allows testing without a mocking framework.
It could look somewhat like this:
public class YourClass {
// ...
public String viewReport() {
try {
boolean isValidRequest = validateRequest();
if (isValidRequest) {
IntegrationReportCsvFileHandler fileHandler = new IntegrationReportCsvFileHandler();
IntegrationReportData inputData = fileHandler.readData(new FileInputStream(DOCUSIGN_REPORT_FILE));
IntegrationReportGenerator generator = new IntegrationReportGenerator();
IntegrationReportData outputData = generator.processData(inputData, getESignUIConfig());
fileHandler.writeReport(outputData, new FileWriter(DOCUSIGN_REPORT_FILE));
} else {
failureResponse(msgs, 400);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
} catch (Exception e) {
e.printStackTrace();
msgs.add(new Message(ESignatureIntegrationMessageTypeEnum.MESSAGE_TYPE_ERROR,
UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_CODE_500, UiIntegrationKeyConstants.UI_INTEGRATION_ERROR_TEXT_SERVICE_ERROR));
failureResponse(msgs, 500);
return UiIntegrationKeyConstants.FAILURE_RESPONSE;
}
return UiIntegrationKeyConstants.REPORT_RESPONSE;
}
// ...
}
public class IntegrationReportData {
// your custom data structure
// may as well just be a List<Data>
// may be different for input and output
}
public class IntegrationReportException extends Exception {
// your custom exception
public IntegrationReportException(String message) { super(exception); }
}
public class IntegrationReportGenerator {
public IntegrationReportData processData(IntegrationReportData data, ESignConfig config) throws IntegrationReportException {
// here's your logic that requires testing
}
}
public class IntegrationReportCsvFileHandler {
public IntegrationReportData readData(InputStream input) throws IOException {
// read data from given input stream
}
public void writeData(IntegrationReportData data, OutputStreamWriter outputWriter) throws IOException {
// write data to given output stream
}
}
That way the IntegrationReportGenerator would be easily testable.
Related
This question already has answers here:
Mocking Files in Java - Mock Contents - Mockito
(3 answers)
Closed 6 years ago.
I have the following code:
public class FolderServiceImpl implements FolderService {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
if (folderStatusFile.exists()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(folderStatusFile));
String line = br.readLine();
status = Integer.parseInt(line);
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
L.warn("could not close reader ", e);
}
}
}
} else {
status = 3;
}
return status;
}
}
I want to test this method without creating actual files for every case. I should be using Java 1.7, JUnit 4, Mockito and/or PowerMockito.
Any ideas on how to do that?
I am talking about mocking either the data source or simply changeing the input for the method.
My test looks something like this:
`#Rule
public TemporaryFolder folder = new TemporaryFolder();
private FolderServiceImpl serviceToTest = new FolderServiceImpl();
private String folderPath;
#Before
public void setUp() {
folderPath = folder.getRoot().getAbsolutePath();
try {
folder.newFile(".folderstatus");
} catch (IOException e) {
e.printStackTrace();
}
}
#Test
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() {
// given
deleteFolderStatusFile();
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(3, status);
}
#Test
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() {
// given
writeStatusToTestFile("Test");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(4, status);
}
#Test
public void shouldReturnFolderStatusInTheFile() {
// given
writeStatusToTestFile("1");
// actual
int status = serviceToTest.getFolderStatus(folderPath);
// expected
assertEquals(1, status);
}
private void writeStatusToTestFile(String status) {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.write(file, status.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private void deleteFolderStatusFile() {
Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus");
try {
Files.delete(file);
} catch (IOException e) {
e.printStackTrace();
}
}`
Although the answer of #BenHeid may work I'd suggest to change to different approach.
IMHO when ever I use PowerMock(-ito) it is a surrender to bad design.
Also the PowerMock solution will confuse test coverage tools since it changes the Applications byte code after it has been instrumented for coverage measurement.
So the approach I'd prefer is to stick to Clean Code and OOP rules.
One of them is separation of concerns.
In your case the method creates some infrastructure classes (dependencies) to work with, namely FileReader and BufferedReader.
But the instantiation of (direct) dependencies is not a responsibility of a class containing business logic.
Therefore I'd suggest to refactor that code out into a separate class:
class ReaderFactory {
public BufferedReader createFor(File file) throws FileNotFoundException {
return new BufferedReader(new FileReader(file));
}
}
Your Class would change to this:
class FolderServiceImpl {
private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class);
private final ReaderFactory readerFactory;
FolderServiceImpl(ReaderFactory readerFactory) {
this.readerFactory = readerFactory;
}
public int getStatus(String folderPath) {
int status = 0;
File folderStatusFile = new File(folderPath, ".folderstatus");
// try "with resource" takes care of closing the reader
try (BufferedReader br = readerFactory.createFor(folderStatusFile);) {
String line = br.readLine();
status = Integer.parseInt(line);
} catch (IOException e) {
status = 3;
} catch (Exception e) {
L.error("can't read file " + folderStatusFile.getAbsolutePath(), e);
status = 4;
}
return status;
}
}
And your Test would be this:
public class FolderServiceImplTest {
private static final String ANY_FILE_NAME = "";
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Rule
public ExpectedException thrown = ExpectedException.none();
#Mock
private ReaderFactory readerFactory;
#InjectMocks
FolderServiceImpl sut;
#Test
public void getStatus_FileNotExisting_returnStatus3() throws Exception {
// arrange
Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class));
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(3));
}
#Test
public void getStatus_ValidFile_returnFileContentAsInt() throws Exception {
// arrange
BufferedReader bufferedReader = Mockito.mock(BufferedReader.class);
Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class));
Mockito.doReturn("4711").when(bufferedReader).readLine();
// act
int status = sut.getStatus(ANY_FILE_NAME);
// assert
Assert.assertThat("status",status,CoreMatchers.equalTo(4711));
}
}
You have to use something like this:
#RunWith(PowerMockRunner.class)
#PrepareForTest(tests.class)
public class test {
#Test
public void test() throws Exception {
File fileMock = Mockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments(Mockito.anyString(), Mockito.anyString()).thenReturn(fileMock);
FolderServiceImpl sut = new FolderServiceImpl sut ();
Mockito.when(fileMock.exists()).thenReturn(true);
sut.getStatus("");
// Your verifications..
}
}
Powermock will mock the File object which is created in the method getStatus of your class. With Mockito.when you can say what is the return value of folderStatusFile.exists() in your code.
EDIT
I have included the following two jars with maven, but you don't need to use maven: https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6 and https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9 and https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19
-> controller.java
public controller() {
public controller(DataInterpreter interpret,ControllerClientUtility util, InterfaceConnection inter) {
interpreter = interpret;
utility = util;
interfaced = inter;
}
}
...
public void closeOne(String vpnSessionId) throws Exception {
try{
if ( interfaced.connect() && (interfaced.CheckIntegrity(SessionId)) ){
interfaced.kill(vpnSessionId);
}else{
closeAll();
}
}catch(Exception e){
if ( e.getMessage().startsWith("INTERFACE_ERR:") ){
closeAll();
}else{
throw new Exception(e);
}
}
}
-> methods in InterfaceConnection.java
public String getReponseFor(String command) throws Exception{
if (send(command)){
return receive();
}
else{
throw new Exception("INTERFACE_ERR: Could not get Response");
}
}
public List<String> getListOfConnections() throws Exception{
String statusResponse = getReponseFor("something");
..(regex searches and then make a list connectionsConnected)
return connectionsConnected;
}
public boolean CheckIntegrity(String SessionId){
try {
List<String> connections = new ArrayList<String>();
connections = getListOfConnections();
if (connections.contains(SessionId)){
return true;
}
return false;
}catch(Exception e){
return false;
}
}
Is there a way to mock the output of getListOfConnections ? I tried doing something like this but did not work
-> controllerTest.java
#Mock private InterfaceConnection interfaced;
#Before
public void beforeTests() throws Exception {
MockitoAnnotations.initMocks(this);
impl = new Controller(interpreter,utility,interfaced);
...
#Test
public void testDisconnectOneSessionWithBadSessionId_sendCommand() throws Exception{
String badSessionId = "123:123";
List<String> mockConnections = new ArrayList<String>();
mockConnections.add("asdasds");
when(interfaced.getListOfConnections()).thenReturn(mockConnections);
impl.closeOne(badSessionId);
Mockito.verify(utility)....
}
I hope I'm clear, thanks in advance.
When I create custom Call class I can't return Response, because Response class is final. Is there any workaround for this?
public class TestCall implements Call<PlacesResults> {
String fileType;
String getPlacesJson = "getplaces.json";
String getPlacesUpdatedJson = "getplaces_updated.json";
public TestCall(String fileType) {
this.fileType = fileType;
}
#Override
public Response execute() throws IOException {
String responseString;
InputStream is;
if (fileType.equals(getPlacesJson)) {
is = InstrumentationRegistry.getContext().getAssets().open(getPlacesJson);
} else {
is = InstrumentationRegistry.getContext().getAssets().open(getPlacesUpdatedJson);
}
PlacesResults placesResults= new Gson().fromJson(new InputStreamReader(is), PlacesResults.class);
//CAN"T DO IT
return new Response<PlacesResults>(null, placesResults, null);
}
#Override
public void enqueue(Callback callback) {
}
//default methods here
//....
}
In my unit test class I want to use it like this:
Mockito.when(mockApi.getNearbyPlaces(eq("testkey"), Matchers.anyString(), Matchers.anyInt())).thenReturn(new TestCall("getplaces.json"));
GetPlacesAction action = new GetPlacesAction(getContext().getContentResolver(), mockEventBus, mockApi, "testkey");
action.downloadPlaces();
My downloadPlaces() method look like:
public void downloadPlaces() {
Call<PlacesResults> call = api.getNearbyPlaces(webApiKey, LocationLocator.getInstance().getLastLocation(), 500);
PlacesResults jsonResponse = null;
try {
Response<PlacesResults> response = call.execute();
Timber.d("response " + response);
jsonResponse = response.body();
if (jsonResponse == null) {
throw new IllegalStateException("Response is null");
}
} catch (UnknownHostException e) {
events.sendError(EventBus.ERROR_NO_CONNECTION);
} catch (Exception e) {
events.sendError(EventBus.ERROR_NO_PLACES);
return;
}
//TODO: some database operations
}
After looking at retrofit2 Response class more thoroughly I've found out that there is a static method that do what I need. So, I simply changed this line:
return new Response<PlacesResults>(null, placesResults, null);
to:
return Response.success(placesResults);
Everything works now.
so i've been sitting above this code for a while , ready the NullPointerException threads, and still can't figure out what is going wrong in my code, so i turn to you.
public class Main {
public static void main(String[] args){
/* Making catalog, loading last state */
Collection catalog = new Collection();
try {
catalog.readFromFile();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
catalog.addShip(new Ship("ABC123", "John", "Suzuki", 50));
}
}
And my Collection class looks like this:
public class Collection {
private List<Ship> shipList;
private String fileName = "catalog.txt";
private int income;
private int space;
public Collection() {
shipList = new ArrayList<Ship>();
income = 0;
space = 500;
File f = new File("catalog.txt");
if(!f.exists()) {
try {
f.createNewFile();
writeToFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void addShip(Ship SHIP){
space -= SHIP.LENGTH;
income += SHIP.COST;
shipList.add(SHIP);
}
public Ship getShip(int INDEX){
return shipList.get(INDEX);
}
public void writeToFile() throws IOException {
FileOutputStream f = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(f);
out.writeObject(shipList);
out.close();
}
#SuppressWarnings("unchecked")
public void readFromFile() throws IOException, ClassNotFoundException {
FileInputStream f = new FileInputStream(fileName);
ObjectInputStream in = new ObjectInputStream(f);
shipList = (ArrayList<Ship>)in.readObject();
in.close();
}
public int getIncome(){
return income;
}
public int getSpace(){
return space;
}
}
My problem is, when i call in main catalog.addship() i get nullptr error. After following the console errors, it says i get the nullptrexc when i call the addShip() on the catalog, following from there i get the error when i add() a Ship to the Collection's shipList. So what i concluded, it is because the shipList in the Collection is uninitialized. But in the constructor i write shipList = new ArrayList<Ship>(); so it is clearly initialized.
The exception stacktrace is the following:
Exception in thread "main" java.lang.NullPointerException
at collection.Collection.addShip(Collection.java:31)
at main.Main.main(Main.java:100)
In your main method, you initialize the ArrayList properly. But then, you make a
catalog.readFromFile()
call. In the readFromFile() method, you re-initialize the ArrayList
shipList = (ArrayList<Ship>)in.readObject();
the in.readObject() is returning null. That is why your shipList variable is null.
Hope this helps!
Java Newbie question :
I need to capture the text being written to a printStream by a 3rd party component.
The PrintStream is defaulted to System.err, but can be changed to another PrintStream.
Looking through the docs, I couldn't find an easy way to direct the contents of a PrintStream to a string writer / buffer.
Can someone please assist?
PipedOutputStream pipeOut = new PipedOutputStream();
PipedInputStream pipeIn = new PipedInputStream(pipeOut);
System.setOut(new PrintStream(pipeOut));
// now read from pipeIn
import java.io.*;
public class Test {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("errors.txt");
} catch(IOException ioe) {
System.err.println("redirection not possible: "+ioe);
System.exit(-1);
}
PrintStream ps = new PrintStream(fos);
System.setErr(ps);
System.err.println("goes into file");
}
}
You can create a PrintStream around any other OutputStream.
The simplest way to create one that goes to a buffer in memory would be:
PrintStream p = new PrintStream( new ByteArrayOutputStream() )
Then you could read and reset the contents of the byte array at whatever points you like.
Another possibility would be to use pipes.
InputStream third_party_output = new PipedInputStream();
PrintStream p = new PrintStream( new PipedOutputStream( third_party_output ) );
Then you could read from the third_party_output stream to get the text written by the library.
Are you looking for something like this?
OutputStream redirect = System.err;
PrintStream myPrintStream = new PrintStream(redirect);
myPrintStream.println("hello redirect");
If you can pass myPrintStream to the 3rd party application, you can redirect it anywhere you want.
I use the following class to log System.out and System.err to a set of rotating files (where xxx-001.log is the most recent). It contains a few call to utility methods, which you will need to implement before it will compile - they should be self-explanatory.
import java.io.*;
import java.lang.reflect.*;
public class LoggerOutputStream
extends OutputStream
{
// *****************************************************************************
// INSTANCE PROPERTIES
// *****************************************************************************
private FileOutputStream log=null; // the base output stream
private String fnmBase,fnmExt; // filename base, file extension
private int fnmCount,fnmLast; // count for filename index, last filename used
private int logSize,totWritten; // max log size, current number of bytes written
// *****************************************************************************
// INSTANCE CONSTRUCTORS/INIT/CLOSE/FINALIZE
// *****************************************************************************
public LoggerOutputStream(String baseFilename) throws IOException {
this(baseFilename,".log",2,1024000);
}
public LoggerOutputStream(String baseFilename, String extension) throws IOException {
this(baseFilename,extension,2,1024000);
}
public LoggerOutputStream(String baseFilename, String extension, int numberOfFiles, int maxFileSize) throws IOException {
fnmBase=baseFilename;
if(Character.isLetterOrDigit(fnmBase.charAt(fnmBase.length()-1))) { fnmBase=(fnmBase+"-"); }
fnmExt=extension;
if(!fnmExt.startsWith(".")) { fnmExt=('.'+fnmExt); }
fnmCount=numberOfFiles;
logSize=maxFileSize;
if(fnmCount>MAXLOGS) { fnmCount=MAXLOGS; }
fnmLast=0;
for(int xa=1; xa<=MAXLOGS; xa++) {
if(!new File(constructFilename(xa)).exists()) {
while((--xa)>fnmCount) { IoUtil.deleteFile(constructFilename(xa)); }
fnmLast=xa;
break;
}
}
log=null;
openFile(false);
if(numberOfFiles>MAXLOGS) { System.out.println("** Log File Count Limited To "+MAXLOGS); }
}
public void close() throws IOException {
close(false);
}
private void openFile(boolean ovrflw) throws IOException {
close(true);
if (fnmLast< fnmCount) { fnmLast++; }
else if(fnmLast==fnmCount) { IoUtil.deleteFile(constructFilename(fnmCount)); }
for(int xa=fnmLast; xa>0; xa--) { IoUtil.renameFile(constructFilename(xa-1),constructFilename(xa)); }
log=new FileOutputStream(constructFilename(1));
totWritten=0;
}
private String constructFilename(int index) {
return constructFilename(fnmBase,index,fnmExt);
}
private synchronized void close(boolean ovrflw) throws IOException {
if(log!=null) {
log.flush();
log.close();
log=null;
}
}
// *****************************************************************************
// INSTANCE METHODS - ACCESSORS
// *****************************************************************************
public String getFilename() {
return constructFilename(1);
}
public String getFilename(int idx) {
return constructFilename(idx);
}
public synchronized void cycleLogFile() throws IOException {
openFile(true);
}
// *****************************************************************************
// INSTANCE METHODS
// *****************************************************************************
public synchronized void flush() throws IOException {
if(log!=null) {
log.flush();
}
}
public synchronized void write(int val) throws IOException {
if(log!=null) {
log.write(val);
totWritten++;
if(val=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
public synchronized void write(byte[] bytes) throws IOException {
if(log!=null) {
log.write(bytes);
totWritten+=bytes.length;
if(bytes.length>0 && bytes[bytes.length-1]=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
public synchronized void write(byte[] bytes, int str, int len) throws IOException {
if(log!=null) {
log.write(bytes,str,len);
totWritten+=len;
if(bytes.length>(str+len-1) && bytes[str+len-1]=='\n') {
if(totWritten>logSize) { openFile(true); }
else { log.flush(); }
}
}
}
// *****************************************************************************
// STATIC PROPERTIES
// *****************************************************************************
static public final int MAXLOGS=999; // maximum log files allowed
// *****************************************************************************
// STATIC METHODS
// *****************************************************************************
static public String constructFilename(String bas, int idx, String ext) {
if(!bas.endsWith("-") && !bas.endsWith("_") && !bas.endsWith(".")) { bas=(bas+"-"); }
if(!ext.startsWith(".") ) { ext=('.'+ext); }
return (bas+TextUtil.raZeros(idx,3)+ext);
}
} /* END PUBLIC CLASS */