Testing outputstream.write(<String>) without creating a file - java

I am testing a output stream in java something like below.
Writer outputStream = getOutputStream(fileName);
if(outputStream != null) {
try {
outputStream.write(inputText);
}
finally {
outputStream.close();
}
}
else {
throw new IOException("Output stream is null");
}
I am write a mockito test as below
public void testFileWrite() throws IOException {
when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(outputStreamMock);
doNothing().when(outputStreamMock).write(Matchers.anyString());
doNothing().when(bufferedReaderMock).close();
testObj.write(outputFileNameValidValue, reveredFileInput);
verify(outputStreamMock).write(Matchers.anyString());
verify(outputStreamMock).close();
}
The problem is when you create OutputStreamWriter(new FileOutputStream(filename)) a physical file on the disk is created.
Can we test Outputstream.write without actually writing a file on the disk?
Thanks
Anand

You can use ByteArrayOutputStream which writes the data in memory. You can read this with a ByteArrayInputStream.
An alternative is to write an expecting OutputStream which fails as soon as you attempt to write an incorrect byte. This can be helpful to see exactly where/why a test fails.

You could try using System.out for your output which is actually a Printstream, which is a subclass of OutputStream
see:
http://docs.oracle.com/javase/6/docs/api/java/lang/System.html
http://docs.oracle.com/javase/6/docs/api/java/io/PrintStream.html

As other suggested already you need to be able to inject a mocked OutputStream in your class under test. As your class under test needs a OutputStream which writes into a given file, you will need to inject a mockable OutputStreamFactory into your class under test.
I have this code for you which is fully self contained:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.IOException;
import java.io.OutputStream;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class Test9328173 {
private ClassUnderTest testObj;
#Mock
private OutputStreamFactory factory;
#Mock
private OutputStream stream;
#Before
public void setUp() throws Exception {
testObj = new ClassUnderTest();
testObj.factory = factory;
}
#Test
public void testFileWrite() throws Exception {
when(factory.create("filename")).thenReturn(stream);
testObj.write("filename", new byte[]{1, 2, 3});
verify(stream).write(new byte[]{1, 2, 3});
verify(stream).close();
}
private class ClassUnderTest {
private OutputStreamFactory factory;
public void write(String filename, byte[] content) throws IOException {
OutputStream stream = factory.create(filename);
try {
stream.write(content);
} finally {
stream.close();
}
}
}
private interface OutputStreamFactory {
OutputStream create(String filename);
}
}

You should mock up your getOutputStream: is should return mocked output stream object. Invocation of new FileOutputStream indeed creates file on disk.
Theoretically you can mock up file system itself but it is much more complicated.
And BTW if(outputStream != null) is redundant: stream can never be null. If it cannot be created the method should throw exception. It is not C, it is Java. :)

You should have the mocked getOutputStream(String) return a java.io.StringWriter and you can then assert that the expected content was written.
public void testFileWrite() throws IOException {
StringWriter writer = new StringWriter();
when(testObj.getOutputStream(outputFileNameValidValue)).thenReturn(writer);
testObj.write(outputFileNameValidValue, reveredFileInput);
assertEquals(reveredFileInput, writer.toString());
verify(writer).close();
}

Related

OutputStream class is used for writing into files. How is it possible?

The below code is quoted from : http://examples.javacodegeeks.com/core-java/io/fileoutputstream/java-io-fileoutputstream-example/
Although the OutputStream is an abstract method, at the below code, OutputStream object is used for writing into the file.
Files.newOutputStream(filepath)) returns OutputStream. Then, the type of out is OutputStream, and out references OutputStream.
How can this be possible while OutputStream is an abstract class?
package com.javacodegeeks.core.io.outputstream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class FileOutputStreamExample {
private static final String OUTPUT_FILE = "C:\\Users\\nikos\\Desktop\\TestFiles\\testFile.txt";
public static void main(String[] args) {
String content = "Hello Java Code Geeks";
byte[] bytes = content.getBytes();
Path filepath = Paths.get(OUTPUT_FILE);
try ( OutputStream out = Files.newOutputStream(filepath)) {
out.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Just because the declared type is OutputStream, that doesn't mean the implementation doesn't create an instance of a concrete subclass of OutputStream. You see this all the time with interfaces. For example:
public List<String> getList() {
return new ArrayList<String>();
}
Basically you need to distinguish between the API exposed (which uses the abstract class) and the implementation (which can choose to use any subclass it wants).
So Files.newOutputStream could be implemented as:
public static OutputStream newOutputStream(Path path)
throws IOException {
return new FileOutputStream(path.toFile());
}

How to mock local variables using mockito or powermock

I have scenario like this
InputStreamReader reader = new InputStreamReader(getFileAsStream(resourceResolver, iconpath));
BufferedReader bReader = new BufferedReader(reader);
I have mocked till this point
getFileAsStream(resourceResolver, iconpath)
now I am getting one reader
BufferedReader bReader = new BufferedReader(reader);
but when I execute this line I get null and not able to move forward
while ((iconEntry = bReader.readLine()) != null)
Please tell me how can I mock this.
Please note I cannot change my main code therefore the solution present on Mockito docs is not valid in my case
Test code
#RunWith(PowerMockRunner.class)
#PrepareForTest({ FrameworkUtil.class, LoggerFactory.class })
public class IconPreviewServletTest {
private IconPreviewServlet iconPreviewServlet;
private SlingHttpServletRequest request;
private SlingHttpServletResponse response;
private Bundle bundle;
private BundleContext bundleContext;
private ServiceReference factoryRef;
private CommonService resolverFactory;
private PrintWriter out;
private ResourceResolver resourceResolver;
private Resource resource;
private Node node;
private Node jcrContent;
private javax.jcr.Property property;
private Binary binary;
private InputStream stream;
private InputStreamReader inputReader;
private BufferedReader reader;
#Before
public void setUp() throws IOException, PathNotFoundException,
RepositoryException {
init();
}
private void init() throws IOException, PathNotFoundException,
RepositoryException {
request = mock(SlingHttpServletRequest.class);
response = mock(SlingHttpServletResponse.class);
bundleContext = mock(BundleContext.class);
factoryRef = mock(ServiceReference.class);
resolverFactory = mock(CommonService.class);
out = mock(PrintWriter.class);
resourceResolver = mock(ResourceResolver.class);
resource = mock(Resource.class);
node = mock(Node.class);
jcrContent = mock(Node.class);
property = mock(Property.class);
binary = mock(Binary.class);
stream=IOUtils.toInputStream("some test data for my input stream");
reader = mock(BufferedReader.class);
inputReader=mock(InputStreamReader.class);
bundle = mock(Bundle.class);
mockStatic(FrameworkUtil.class);
mockStatic(LoggerFactory.class);
Logger log = mock(Logger.class);
when(LoggerFactory.getLogger(IconPreviewServlet.class)).thenReturn(log);
when(FrameworkUtil.getBundle(CommonService.class)).thenReturn(bundle);
when(bundle.getBundleContext()).thenReturn(bundleContext);
when(bundleContext.getServiceReference(CommonService.class.getName()))
.thenReturn(factoryRef);
when(bundleContext.getService(factoryRef)).thenReturn(resolverFactory);
when(request.getParameter("category")).thenReturn("category");
when(request.getParameter("query")).thenReturn("query");
when(response.getWriter()).thenReturn(out);
when(request.getResourceResolver()).thenReturn(resourceResolver);
when(
resourceResolver
.getResource("/etc/designs/resmed/icons/category/icons.txt"))
.thenReturn(resource);
when(resource.adaptTo(Node.class)).thenReturn(node);
when(node.getNode("jcr:content")).thenReturn(jcrContent);
when(jcrContent.getProperty("jcr:data")).thenReturn(property);
when(property.getBinary()).thenReturn(binary);
when(binary.getStream()).thenReturn(stream);
}
To make this work, you need to use Powermockito to intercept the constructor calls (new InputStreamReader(...), new BufferedReader(...)) so that your mocks get returned. An example is below. In your case, just intercepting the new BufferedReader call may be enough.
Assume the following is the code you want to test:
package test;
import java.io.*;
public class SUT {
public String doSomething() throws IOException {
InputStreamReader reader =
new InputStreamReader(getFileAsStream(null, null));
BufferedReader bReader =
new BufferedReader(reader);
return bReader.readLine();
}
private InputStream getFileAsStream(Object resourceResolver, Object iconPath)
throws FileNotFoundException {
return new ByteArrayInputStream("".getBytes());
}
}
The following test code is an example of how to intercept the constructor calls:
package test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import static org.junit.Assert.assertEquals;
import static org.powermock.api.mockito.PowerMockito.doReturn;
import static org.powermock.api.mockito.PowerMockito.mock;
#RunWith(PowerMockRunner.class)
#PrepareForTest({ SUT.class })
public class SUTTest {
#Test
public void doSomethingReturnsValueFromBufferedReader() throws Exception {
// Arrange
SUT sut = new SUT();
InputStreamReader inputStreamReaderMock = mock(InputStreamReader.class);
BufferedReader bufferedReaderMock = mock(BufferedReader.class);
// Set your mocks up to be returned when the new ...Reader calls
// are executed in sut.doSomething()
PowerMockito.whenNew(InputStreamReader.class).
withAnyArguments().thenReturn(inputStreamReaderMock);
PowerMockito.whenNew(BufferedReader.class).
withArguments(inputStreamReaderMock).
thenReturn(bufferedReaderMock);
// Set the value you want bReader.readLine() to return
// when sut.doSomething() executes
final String bufferedReaderReturnValue = "myValue";
doReturn(bufferedReaderReturnValue).when(bufferedReaderMock).readLine();
// Act
String result = sut.doSomething();
// Assert
assertEquals(bufferedReaderReturnValue, result);
}
}
This hopefully helps you in your immediate problem. However, it seems to me that what you're creating will be a very slow, confusing and brittle test. Right now, you're mocking so much that it makes very hard to determine what you're actually trying to test.
The high amount of mocking probably indicates that the design of the code you're testing would need some work to improve testability. If you can't touch the code, then you can't - but try to make your test more readable and intuitive ("When this method is invoked, this thing should happen, because...").
to make this line work:
while ((iconEntry = bReader.readLine()) != null)
you must determine how many lines you want to read and add this to your test code:
when(bReader.readLine()).thenReturn("line number one").thenReturn("line number two");

Java - System.setOut does not save an exception message

It seems that System.setOut() does not work in this test case.
Here are problem description.
test0 executes System.setOut(new PrintStream(byteBuffer)) so that it stores standard output.
test0 invokes AddChild1_wy_v1.main.
In the AddChild1_wy_v1.main, xml.addChild(null) generates an exception message.
The exception message should be stored in byteBuffer, but it seems it wasn't.. JVM stops running the test case once the exception message pops up. And the remaining code after AddChild1_wy_v1.main are not executed.
Is there a way for jvm to execute the remaining code in test0?
NanoAddChild1_wy_v1Tests.java
package tests;
import junit.framework.TestCase;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import net.n3.nanoxml.*;
public class NanoAddChild1_wy_v1Tests extends TestCase {
public void test0() throws Exception { //addchild1.out
String result;
ByteArrayOutputStream byteBuffer;
byteBuffer = new ByteArrayOutputStream();
System.setOut(new PrintStream(byteBuffer));
AddChild1_wy_v1.main(new String[] {"/home/junghyun/Dev/nanoxml/inputs/simple.xml"});
result = new String(byteBuffer.toByteArray());
assertEquals(result, "Exception in thread \"main\" java.lang.IllegalArgumentException: child must not be null\n\tat net.n3.nanoxml.XMLElement.addChild(XMLElement.java:165)\n\tat AddChild1_wy_v1.main(AddChild1_wy_v1.java:47)\n");
}
}
AddChild1_wy_v1.java
package tests;
import net.n3.nanoxml.IXMLParser;
import net.n3.nanoxml.IXMLReader;
import net.n3.nanoxml.StdXMLReader;
import net.n3.nanoxml.XMLElement;
import net.n3.nanoxml.XMLParserFactory;
import net.n3.nanoxml.XMLWriter;
public class AddChild1_wy_v1
{
public static void main(String args[])
throws Exception
{
if (args.length == 0) {
System.err.println("Usage: java DumpXML file.xml");
Runtime.getRuntime().exit(1);
}
IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
IXMLReader reader = StdXMLReader.fileReader(args[0]);
parser.setReader(reader);
XMLElement xml = (XMLElement) parser.parse();
xml.addChild (null);
(new XMLWriter(System.out)).write(xml);
}
}
There's 3 default streams:
System.in : InputStream
System.out :PrintStream
System.err :PrintStream
So to set each one there is 3 methods:
public static void setIn(InputStream in) {...}
public static void setOut(PrintStream out) {...}
public static void setErr(PrintStream err) {...}
To set System.err you must use System.setErr(yourStream);
For another question: you just need to use
try {
//throwing exception
} catch (Exception e) {
//act on exception
}
It seems to me that you never write that Exception at all.
You just throw it upwards. Try catch it and have ex.printStackTrace();
Also that will go to standard error, unless you specifically say otherwise.
As by your request I will leave the test0 method unaltered, you can use it the way it is.
in AddChild1_wy_v1.java:
public class AddChild1_wy_v1 {
public static void main(String args[]) // note that I don't throw the Exception.
{
try {
if (args.length == 0) {
System.err.println("Usage: java DumpXML file.xml");
Runtime.getRuntime().exit(1);
}
IXMLParser parser = XMLParserFactory.createDefaultXMLParser();
IXMLReader reader = StdXMLReader.fileReader(args[0]);
parser.setReader(reader);
XMLElement xml = (XMLElement) parser.parse();
xml.addChild (null);
(new XMLWriter(System.out)).write(xml);
} catch (Exception any) {
any.printStackTrace(System.out); // note that I send the Stack Trace to standard out here.
}
}
}
Wrap your method call in a try-catch to continue past the exception:
try {
AddChild1_wy_v1.main(...);
} catch(Throwable t) {
t.printStackTrace();
}
// the rest of your code will execute
Exceptions are printed to standard error, not standard output. Try System.setErr.
Never post images of your code.

Redirect console output to string in Java

I have one method whose return type is void and it prints directly on console.
However I need that output in a String so that I can work on it.
As I can't make any changes to the method with return type void I have to redirect that output to a String.
How can I redirect it in Java?
If the function is printing to System.out, you can capture that output by using the System.setOut method to change System.out to go to a PrintStream provided by you. If you create a PrintStream connected to a ByteArrayOutputStream, then you can capture the output as a String.
Example:
// Create a stream to hold the output
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
// IMPORTANT: Save the old System.out!
PrintStream old = System.out;
// Tell Java to use your special stream
System.setOut(ps);
// Print some output: goes to your special stream
System.out.println("Foofoofoo!");
// Put things back
System.out.flush();
System.setOut(old);
// Show what happened
System.out.println("Here: " + baos.toString());
This program prints just one line:
Here: Foofoofoo!
Here is a utility Class named ConsoleOutputCapturer. It allows the output to go to the existing console however behind the scene keeps capturing the output text. You can control what to capture with the start/stop methods. In other words call start to start capturing the console output and once you are done capturing you can call the stop method which returns a String value holding the console output for the time window between start-stop calls. This class is not thread-safe though.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
public class ConsoleOutputCapturer {
private ByteArrayOutputStream baos;
private PrintStream previous;
private boolean capturing;
public void start() {
if (capturing) {
return;
}
capturing = true;
previous = System.out;
baos = new ByteArrayOutputStream();
OutputStream outputStreamCombiner =
new OutputStreamCombiner(Arrays.asList(previous, baos));
PrintStream custom = new PrintStream(outputStreamCombiner);
System.setOut(custom);
}
public String stop() {
if (!capturing) {
return "";
}
System.setOut(previous);
String capturedValue = baos.toString();
baos = null;
previous = null;
capturing = false;
return capturedValue;
}
private static class OutputStreamCombiner extends OutputStream {
private List<OutputStream> outputStreams;
public OutputStreamCombiner(List<OutputStream> outputStreams) {
this.outputStreams = outputStreams;
}
public void write(int b) throws IOException {
for (OutputStream os : outputStreams) {
os.write(b);
}
}
public void flush() throws IOException {
for (OutputStream os : outputStreams) {
os.flush();
}
}
public void close() throws IOException {
for (OutputStream os : outputStreams) {
os.close();
}
}
}
}
Although this question is very old and has already very good answers I want to provide an alternative. I created a library specifically for this use case. It is called Console Captor and you can add it with the following snippet:
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>consolecaptor</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
Example class
public class FooService {
public void sayHello() {
System.out.println("Keyboard not responding. Press any key to continue...");
System.err.println("Congratulations, you are pregnant!");
}
}
Unit test
import static org.assertj.core.api.Assertions.assertThat;
import nl.altindag.console.ConsoleCaptor;
import org.junit.jupiter.api.Test;
public class FooServiceTest {
#Test
public void captureStandardAndErrorOutput() {
ConsoleCaptor consoleCaptor = new ConsoleCaptor();
FooService fooService = new FooService();
fooService.sayHello();
assertThat(consoleCaptor.getStandardOutput()).contains("Keyboard not responding. Press any key to continue...");
assertThat(consoleCaptor.getErrorOutput()).contains("Congratulations, you are pregnant!");
consoleCaptor.close();
}
}
If you are using Spring Framework, there is a really easy way to do this with OutputCaptureExtension:
#ExtendWith(OutputCaptureExtension.class)
class MyTest {
#Test
void test(CapturedOutput output) {
System.out.println("ok");
assertThat(output).contains("ok");
System.err.println("error");
}
#AfterEach
void after(CapturedOutput output) {
assertThat(output.getOut()).contains("ok");
assertThat(output.getErr()).contains("error");
}
}

Why am I getting a NullPointerException when trying to read a file?

I use this test to convert txt to pdf :
package convert.pdf;
//getResourceAsStream(String name) : Returns an input stream for reading the specified resource.
//toByteArray : Get the contents of an InputStream as a byte[].
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import convert.pdf.txt.TextConversion;
public class TestConversion {
private static byte[] readFilesInBytes(String file) throws IOException {
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
private static void writeFilesInBytes(byte[] file, String name) throws IOException {
IOUtils.write(file, new FileOutputStream(name));
}
//just change the extensions and test conversions
public static void main(String args[]) throws IOException {
ConversionToPDF algorithm = new TextConversion();
byte[] file = readFilesInBytes("/convert/pdf/text.txt");
byte[] pdf = algorithm.convertDocument(file);
writeFilesInBytes(pdf, "text.pdf");
}
}
Problem:
Exception in thread "main" java.lang.NullPointerException
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1025)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:999)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:218)
at convert.pdf.TestConversion.readFilesInBytes(TestConversion.java:17)
at convert.pdf.TestConversion.main(TestConversion.java:28)
I use the debugger, and the problem seems to be located here :
private static byte[] readFilesInBytes(String file) throws IOException {
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
What is my problem?
Sounds like the resource probably doesn't exist with that name.
Are you aware that Class.getResourceAsStream() finds a resource relative to that class's package, whereas ClassLoader.getResourceAsStream() doesn't? You can use a leading forward slash in Class.getResourceAsStream() to mimic this, so
Foo.class.getResourceAsStream("/bar.png")
is roughly equivalent to
Foo.class.getClassLoader().getResourceAsStream("bar.png")
Is this actually a file (i.e. a specific file on the normal file system) that you're trying to load? If so, using FileInputStream would be a better bet. Use Class.getResourceAsStream() if it's a resource bundled in a jar file or in the classpath in some other way; use FileInputStream if it's an arbitrary file which could be anywhere in the file system.
EDIT: Another thing to be careful of, which has caused me problems before now - if this has worked on your dev box which happens to be Windows, and is now failing on a production server which happens to be Unix, check the case of the filename. The fact that different file systems handle case-sensitivity differently can be a pain...
Are you checking to see if the file exists before you pass it to readFilesInBytes()? Note that Class.getResourceAsStream() returns null if the file cannot be found. You probably want to do:
private static byte[] readFilesInBytes(String file) throws IOException {
File testFile = new File(file);
if (!testFile.exists()) {
throw new FileNotFoundException("File " + file + " does not exist");
}
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
or better yet:
private static byte[] readFilesInBytes(String file) throws IOException {
InputStream stream = TestConversion.class.getResourceAsStream(file);
if (stream == null) {
throw new FileNotFoundException("readFilesInBytes: File " + file
+ " does not exist");
}
return IOUtils.toByteArray(stream);
}
This class reads a TXT file in the classpath and uses TextConversion to convert to PDF, then save the pdf in the file system.
Here TextConversion code :
package convert.pdf.txt;
//Conversion to PDF from text using iText.
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import convert.pdf.ConversionToPDF;
import convert.pdf.ConvertDocumentException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
public class TextConversion implements ConversionToPDF {
public byte[] convertDocument(byte[] documents) throws ConvertDocumentException {
try {
return this.convertInternal(documents);
} catch (DocumentException e) {
throw new ConvertDocumentException(e);
} catch (IOException e) {
throw new ConvertDocumentException(e);
}
}
private byte[] convertInternal(byte[] documents) throws DocumentException, IOException {
Document document = new Document();
ByteArrayOutputStream pdfResultBytes = new ByteArrayOutputStream();
PdfWriter.getInstance(document, pdfResultBytes);
document.open();
BufferedReader reader = new BufferedReader( new InputStreamReader( new ByteArrayInputStream(documents) ) );
String line = "";
while ((line = reader.readLine()) != null) {
if ("".equals(line.trim())) {
line = "\n"; //white line
}
Font fonteDefault = new Font(Font.COURIER, 10);
Paragraph paragraph = new Paragraph(line, fonteDefault);
document.add(paragraph);
}
reader.close();
document.close();
return pdfResultBytes.toByteArray();
}
}
And here the code to ConversionToPDF :
package convert.pdf;
// Interface implemented by the conversion algorithms.
public interface ConversionToPDF {
public byte[] convertDocument(byte[] documentToConvert) throws ConvertDocumentException;
}
I think the problem come from my file system (devbox on windows and server is Unix).
I will try to modify my classpath.
This problem may be caused by calling methods on test.txt, which can be a folder shortcut. In other words, you're calling a method on a file that doesn't exist, resulting in a NullPointerException.

Categories

Resources