I have a class with several tests, which if run alone pass. Instead, if I run the entire test class, only one passes.
I am testing if the output (ie a String) is equal to an expected String. The output is produced by a method, which requires user keyboard input. In each test, I mock the user input with the following class:
import java.io.*;
import java.nio.charset.Charset;
public class MockInOut {
private PrintStream orig;
private InputStream irig;
private ByteArrayOutputStream os;
private ByteArrayInputStream is;
private final static Charset charset = Charset.defaultCharset();
public MockInOut(String input) {
orig = System.out;
irig = System.in;
os = new ByteArrayOutputStream();
try {
System.setOut(new PrintStream(os, false, charset.name()));
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
is = new ByteArrayInputStream(input.getBytes());
System.setIn(is);
}
/**
* Returns everything written to System.out since this {#code MockInOut} was
* constructed. Can't be called on a closed {#code MockInOut}
*/
public String getOutput() {
if (os != null) {
try {
return os.toString(charset.name()).replace("\r\n", "\n");
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException(ex);
}
} else {
throw new Error("getOutput on closed MockInOut!");
}
}
/**
* Restores System.in and System.out
*/
public void close() {
os = null;
is = null;
System.setOut(orig);
System.setIn(irig);
}
}
Each test is structured as follows:
#Test
MyClassForConstructor myclassfc = new MyClassForConstructor();
MyClass myclass = new MyClass(myclassfc);
MockInOut userkeyboardinput = new MockInOut("firstLineInput\nsecondLineInput\nthirdLineInput\n");
MyObject myobToGetTested = myclass.methodThatRequiresInput();
MyObject myobExpected = new MyObject(String par1, String par2, String par3);
assertEquals(myobExpected.toString(), myobToGetTested.toString());
userkeyboardinput.close();
Each test has the same structure and what it changes is the keyboard input and the parameters to create the expected object.
Every test throws a NoSuchElementException at Scanner.throwFor() because needInput = false, at Scanner.next(), except for one test (always the same, but which has no explicit difference with the others: in the test that passes, I saw that needInput is set true, but I don't know the reason).
I really don't know what else could be done, thanks for everybody who will help!
Related
Let's assume that I have a java program that creates a report by multiple threads writing .to a file:
public File report = new File("C:\somewhere\file")
public FileWriter fileWriter = new FileWriter("C:\somewhere\file");
//Some thread executed the following statement
fileWriter.write("creating report for this thread");
Instead of using a file, I want to use some type of String buffer to create the report so I can return it in a rest response. What can I use that has the same outcome as if using a File.
Update: I want to completely omit the file implementation as I can't store it in cloud.
You can use the outputstream of the HttpServletResponse to send the file as stream. Don't forget to make your header relevant. You can write a method to process the output as file:
public static void writeFileToOutputStream(HttpServletResponse response, File file) {
String type = "application/octet-stream";
response.setContentType(type);
response.setHeader("Content-Disposition", String.format("inline;filename=\"" + file.getName() + "\""));
response.setContentLength((int) file.length());
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
FileCopyUtils.copy(inputStream, response.getOutputStream());
} catch (IOException e) {
log.info("------couldn't write file------");
}
}
Several threads writing to the same would have one obvious solution: use java.util.logging. Writing to a log file. The content of a log file can also easily be returned as a REST response.
Using a string buffer, StringBuilder is faster, but not thread-safe. The older StringBuffer is thread-safe but not with twice appending, like in:
sb.append("The size is ").append(size); // Not thread-safe.
You could do:
private final StringBuilder sb = new StringBuilder(4096);
public void printf(String messageFormat, Object... args) {
String s = new MessageFormat(....);
synchronized(sb) {
sb.append(s);
}
}
public String extract() {
String s;
synchronized(sb) {
s = sb.toString();
sb.setLength(0);
}
return s;
}
If you want to stay implementation agnostic then you should design to an interface. I'd suggest just plain old Writer. You could have something like:
public abstract class AbstractReportWriter {
protected Writer writer;
public AbstractWriter(Writer w) {
writer = w;
}
public void write(String text) {
writer.write(text);
}
}
public class FileReportWriter extends AbstractReportWriter {
public FileReportWriter(String path) {
super(new FileWriter(path))
}
}
public class StringReportWriter extends AbstractReportWriter {
public StringReportWriter() {
super(new StringWriter())
}
public String getValue() {
return ((StringWriter) writer).toString()
}
}
public class CloudReportWriter extends AbstractReportWriter {
public CloudReportWriter() {
super(new YourCloudWriterClass());
}
}
Then you can pick and choose your writer by just swapping the implementation.
There is a task to read a text file in a producer paradigm. The producer interface is defined as the following:
public interface Producer<ITEM> {
/**
* Produces the next item.
*
* #return produced item
*/
ITEM next();
/**
* Tells if there are more items available.
*
* #return true if there are more items, false otherwise
*/
boolean hasNext();
}
Current code to read the text file is:
public static void readTextFile(File file, Charset charset, Consumer<String> consumer) {
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(file), charset);
BufferedReader in = new BufferedReader(isr, BUFFER_SIZE)) {
String line;
while ((line = in.readLine()) != null) {
consumer.accept(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
The task is to convert it into a:
public static Producer<String> readTextFileRetProducer(File file, Charset charset) {
// ???
return null;
}
Then there goes a list of issues:
How to support hasNext properly given that it requires reading a text line in advance.
How to properly manage exceptions?
How to properly release external resources given that a handy try-with-resources block would no longer be available in the producer paradigm?
P.S. Resources are to be released after the last line from the file has been read. (It is produced after).
P.P.S. If there are libraries and/or code references I could use as a guide to my task, please share them.
Quick and dirty:
public static Producer<String> readFile(File file, Charset charset) {
Stream<String> stream;
try {
stream = Files.lines(file.toPath(), charset);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Iterator<String> iter = stream.iterator();
return new Producer<String>() {
#Override
public boolean hasNext() {
if (!iter.hasNext()) {
stream.close();
return false;
}
return true;
}
#Override
public String next() {
return iter.next();
}
};
}
I'm using JUnit to test my program that has console input, and I use ByteArrays to simulate console input and output. But for some reason, when I use System.setIn(IS) at the end of the first test, it doesn't actually change System.in. Also in second test, when I try to put new ByteArray as System.in, it doesn't happend and my second test fails to pass... So why is that the case?
Edit: My Utility class uses Scanner to read from System.in. :
public static String readText() {
while (true) {
String unos = sc.nextLine();
if (!unos.isEmpty()) {
return unos;
}
System.out.println("Niste ništa uneli, pokušajte ponovo: ");
}
}
public static String read() {
String unos = sc.nextLine();
return unos;
}
And these are my tests:
private final InputStream IS = System.in;
private final PrintStream PS = System.out;
#Test
public void testRead() {
ByteArrayInputStream in = new ByteArrayInputStream("\nNeki tekst\nasdasdasd".getBytes());
System.setIn(in);
assertEquals("", Utility.read());
assertEquals("Neki tekst", Utility.read());
System.setIn(IS);
}
#Test
public void testReadText() {
ByteArrayInputStream in = new ByteArrayInputStream("\nNeki tekst2\n".getBytes());
System.setIn(in);
ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out));
assertEquals("Neki tekst2", Utility.readText());
assertEquals("Niste ništa uneli, pokušajte ponovo: " + System.getProperty("line.separator"), out.toString());
System.setIn(IS);
System.setOut(PS);
}
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
I have a Java program that outputs some text into console. It uses print, println, and some other methods to do this.
At the end of the program , I want to read all the text in console and copy it into a String buffer. How could I do this in Java ? I need to read stdout and stderr separately.
Ok, this was a fun problem. Dosen't seem to be an elegant way of solving it for all PrintStream methods at once. (Unfortunately there is no FilterPrintStream.)
I did write up an ugly reflection-based workaround though (not to be used in production code I suppose :)
class LoggedPrintStream extends PrintStream {
final StringBuilder buf;
final PrintStream underlying;
LoggedPrintStream(StringBuilder sb, OutputStream os, PrintStream ul) {
super(os);
this.buf = sb;
this.underlying = ul;
}
public static LoggedPrintStream create(PrintStream toLog) {
try {
final StringBuilder sb = new StringBuilder();
Field f = FilterOutputStream.class.getDeclaredField("out");
f.setAccessible(true);
OutputStream psout = (OutputStream) f.get(toLog);
return new LoggedPrintStream(sb, new FilterOutputStream(psout) {
public void write(int b) throws IOException {
super.write(b);
sb.append((char) b);
}
}, toLog);
} catch (NoSuchFieldException shouldNotHappen) {
} catch (IllegalArgumentException shouldNotHappen) {
} catch (IllegalAccessException shouldNotHappen) {
}
return null;
}
}
...that can be used like this:
public class Test {
public static void main(String[] args) {
// Create logged PrintStreams
LoggedPrintStream lpsOut = LoggedPrintStream.create(System.out);
LoggedPrintStream lpsErr = LoggedPrintStream.create(System.err);
// Set them to stdout / stderr
System.setOut(lpsOut);
System.setErr(lpsErr);
// Print some stuff
System.out.print("hello ");
System.out.println(5);
System.out.flush();
System.err.println("Some error");
System.err.flush();
// Restore System.out / System.err
System.setOut(lpsOut.underlying);
System.setErr(lpsErr.underlying);
// Print the logged output
System.out.println("----- Log for System.out: -----\n" + lpsOut.buf);
System.out.println("----- Log for System.err: -----\n" + lpsErr.buf);
}
}
Resulting output:
hello 5
Some error
----- Log for System.out: -----
hello 5
----- Log for System.err: -----
Some error
(Note though, that the out field in FilterOutputStream is protected and documented, so it is part of the API :-)
You can't do that once the program is finished running. You need to do it before the program starts to write output.
See this article(archive.org) for details on how to replace stdout and stderr. The core calls are System.setOut() and System.setErr().
You can use PipedInputStream and PipedOutputStream.
//create pairs of Piped input and output streasm for std out and std err
final PipedInputStream outPipedInputStream = new PipedInputStream();
final PrintStream outPrintStream = new PrintStream(new PipedOutputStream(
outPipedInputStream));
final BufferedReader outReader = new BufferedReader(
new InputStreamReader(outPipedInputStream));
final PipedInputStream errPipedInputStream = new PipedInputStream();
final PrintStream errPrintStream = new PrintStream(new PipedOutputStream(
errPipedInputStream));
final BufferedReader errReader = new BufferedReader(
new InputStreamReader(errPipedInputStream));
final PrintStream originalOutStream = System.out;
final PrintStream originalErrStream = System.err;
final Thread writingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
System.setOut(outPrintStream);
System.setErr(errPrintStream);
// You could also set the System.in here using a
// PipedInputStream
DoSomething();
// Even better would be to refactor DoSomething to accept
// PrintStream objects as parameters to replace all uses of
// System.out and System.err. DoSomething could also have
// an overload with DoSomething() calling:
DoSomething(outPrintStream, errPrintStream);
} finally {
// may also want to add a catch for exceptions but it is
// essential to restore the original System output and error
// streams since it can be very confusing to not be able to
// find System.out output on your console
System.setOut(originalOutStream);
System.setErr(originalErrStream);
//You must close the streams which will auto flush them
outPrintStream.close();
errPrintStream.close();
}
} // end run()
}); // end writing thread
//Start the code that will write into streams
writingThread.start();
String line;
final List<String> completeOutputStreamContent = new ArrayList<String>();
while ((line = outReader.readLine()) != null) {
completeOutputStreamContent.add(line);
} // end reading output stream
final List<String> completeErrorStreamContent = new ArrayList<String>();
while ((line = errReader.readLine()) != null) {
completeErrorStreamContent.add(line);
} // end reading output stream
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();
}
}
}
}
Don't do it afterwards, create two StringBuilder objects before the first System.out.print() gets called and just append every string you want to save to the appropriate StringBuilder.
These two line of code will put your output in a text file or u can change the destination as u require.
// Create a file:
System.setOut(new PrintStream( new FileOutputStream("D:/MyOutputFile.txt")));
// Redirect the output to the file:
System.out.println("Hello to custom output stream!");
hope its help u .. :)