Testing output of void main with Console.readline() involved - java

I need to junit test an existing code by the output ( in system.out )
public static void main(String args[])
{
Console console = System.console();
String str = console.readLine();
System.out.println("halo"+str);
}
Since the console.readline is waiting for user input, I found it will halt in the console.readline(),thus block me from getting the output.
Is there a way to do this? Is it posible to do it using Mockito or something?

It is nearly impossible to test code that works with System.console(), because you System.console() always retuns null in tests. Additionally Console is final class without a public constructor.
I recommend to work with the writers and readers of Console and test the code that works with the writers and readers.
public static void main(String args[]) {
Console console = System.console();
BufferedReader reader = new BufferedReader(console.reader());
main2(reader, console.writer(), args);
}
static void main2(BufferedReader reader, Writer writer, String args[] {
String str = reader.readline();
System.out.println("halo"+str);
}
Output to System.out can be tested with the StandardOutputStreamLog rule of the System Rules library. But in your code it is much easier to write to the Console's writer instead of System.out.

The main method is not a good candidate for unit testing. It is just an entry point for an application. Probably, you need to refactor your class to some kind of dependency injection. For example:
public class Something {
private final LinesProvider linesProvider;
public Something(LinesProvider linesProvider) {
this.linesProvider = linesProvider;
}
public void sayHello() {
String str = linesProvider.readLine();
System.out.println("halo "+str);
}
public static void main(String args[]) {
new Something(new LinesProvider() {
private final Console console = System.console();
#Override
public String readLine() {
return console.readLine();
}
}).sayHello();
}
}
interface LinesProvider {
String readLine();
}
Then, you can test the system output like shown below, though it's not a good practice. Instead, try to separate I/O logic from application logic:
public class TestSomething {
private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
private PrintStream printStream = new PrintStream(outputStream, true);
#Before
public void setUp() {
System.setOut(printStream);
}
#Test
public void test() {
new Something(new LinesProvider() {
#Override
public String readLine() {
return "Vasya";
}
}).sayHello();
assertEquals("halo Vasya" + System.getProperty("line.separator"), new String(outputStream.toByteArray()));
}
}

The following test will work, using the JMockit mocking API:
#Test
public void testMyApp(#Mocked final Console console)
{
new NonStrictExpectations(System.class) {{
System.console(); result = console;
console.readLine(); result = " test";
}};
OutputStream output = new ByteArrayOutputStream();
System.setOut(new PrintStream(output));
MyApp.main(new String[0]);
String lineSep = System.getProperty("line.separator");
assertEquals("halo test" + lineSep, output.toString());
}

Related

jUnit Testing: Trying to write a test where I can input empty string to the function and I want to assert that the return value is null

Trying to write a test where I can input empty string to the function and I want to assert that the return value is null.
Attached is my code snippet I am using:
public String getUserInputNess() {
String inputLine = null;
try {
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
inputLine = is.readLine();
if (inputLine.length() == 0)
return null;
} catch (IOException e) {
System.out.println("IOException: " + e);
}
return inputLine.toLowerCase();
}
And below is my Unit test setup:
private void provideInput(String data) {
testIn = new ByteArrayInputStream(data.getBytes());
System.setIn(testIn);
}
private String getOutput() {
return testOut.toString();
}
#After
public void restoreSystemInputOutput() {
System.setIn(systemIn);
System.setOut(systemOut);
}
#Test
public void testGetUserInput() {
/*
Testing the getUserInput method by passing a user input and checking
if it is returned
*/
final String testString = "";
provideInput(testString);
GameHelper game = new GameHelper();
String output = game.getUserInput("");
assertNull(output);
}
Thanks for your help and time in advance
The problem here is that static access hides dependencies.
Your code under test (cut) uses System.in as a dependency. The proper way to deal with that would be to inject this dependency into your cut. The way I suggest is to do this via a constructor parameter. The constructor then assigns it to a final member variable.
If you do so you can at test time pass a test double into your cut instead of the real dependency.

Java equivalent to python's "with"

Python has a nice feature: the "with" statement. It's useful for making global changes that affect all code called within the statement.
e.g. you could define a class CapturePrintStatements to capture all print statements called within the "with"
with CapturePrintStatements() as c:
print 'Stuff Done'
print 'More Stuff Done'
assert c.get_text() == 'Stuff Done'
Is there an equivalent in Java?
try-with-resources is its Java equivalent, and is available in Java 7 and up.
That gives you the possibility to work with resources that need to be explicitly closed, without worrying about closing them. For the example:
Before Java7:
InputStream input = null;
try {
input = new FileInputStream("myFile.txt");
} finally {
if(input != null){
input.close();
}
}
Java 7 & up:
try(FileInputStream input = new FileInputStream("myFile.txt")) {
// Do something with the InputStream
}
This is the try-with-resources construct. When the execution flow will go out of the try block, the FileInputStream will be closed automatically. This is due to the fact that FileInputStream implements the AutoCloseable interface.
As Mohammed noted, you can use try-with-resources. In this case, you want to have your own resource, and it is not really difficult to do.
Creating an auto-closeable class
First, your class should implement AutoCloseable:
public class CaptureOutput implements AutoCloseable {
When constructing this class, you should
store the old System.out,
create a PrintStream to replace it (cf. Java: PrintStream to String?) and
replace the default stream with System.setOut().
Here is how we do it
public CaptureOutput() {
this.stream = new ByteArrayOutputStream();
this.out = System.out;
System.setOut(new PrintStream(stream));
}
The secret is the AutoCloseable.close() method: you just undo your replacement there:
public void close() throws Exception {
System.setOut(this.out);
}
Finally, you need a method to retrieve the content:
public String getContent() {
return this.stream.toString();
}
Using try-with-resources
Done that, just pass the CaptureOutput to the try clause. The code below, for example...
public static void main(String[] args) throws Exception {
String content = null;
System.out.println("This will be printed");
try (CaptureOutput co = new CaptureOutput()) {
System.out.println("EXAMPLE");
content = co.getContent();
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + content);
}
...will result on this:
This will be printed
This will be printed, too.
The content of the string is EXAMPLE
Scope issues
Note that we do not call co.getContent() at the last line. It is not possible because, unlike Python, the co variable is scoped inside the try clause. Once the try block finishes, it is gone.[1] That's why we get the value from inside the block.
Not that elegant, right? A solution may be to give the BAOS to the CaptureOutput constructor:
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
Now, we just use the stream later:
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
(Also, it is not possible to create the CaptureOutput variable before the try. That makes sense: AutoCloseable objects are supposed to be "closed" after their use. What's the use of a closed file, after all? Our use case is a bit different from that, so we have to rely on alternatives.)
The full classes
And here are the full classes:
CaptureOutput.java:
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
public class CaptureOutput implements AutoCloseable {
private ByteArrayOutputStream stream;
private PrintStream out;
public CaptureOutput(ByteArrayOutputStream stream) {
this.stream = stream;
this.out = System.out;
System.setOut(new PrintStream(this.stream));
}
public CaptureOutput() {
this(new ByteArrayOutputStream());
}
#Override
public void close() throws Exception {
System.setOut(this.out);
}
public String getContent() {
return this.stream.toString();
}
}
Main.java:
import java.io.ByteArrayOutputStream;
public class Main {
public static void main(String[] args) throws Exception {
System.out.println("This will be printed");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try (CaptureOutput co = new CaptureOutput(stream)) {
System.out.println("EXAMPLE");
}
System.out.println("This will be printed, too.");
System.out.println("The content of the string is " + stream.toString());
}
}

How do I create stubs for IO files to unit test in Java?

For a testing course assignment, I need to create unit tests for my already-coded system using JUnit. My system is heavily dependent on each other and it also writes/reads from a couple of text files on my disk.
I realize I have to eliminate all dependancies to successfully unit test, I just don't know how to create stubs for Files.
Any help in code, tools or concepts is welcome
import Objs.*;
import java.io.*;
import java.net.URL;
import java.util.Scanner;
/**
*This class communicates with the users file by writing to it, reading from it, searching, deleting...
*
*/
public class users {
public static File usersFile = new File("usersFile.txt");
public static PrintWriter writer;
static Scanner read ;
public static void write(userObj u){
try {
String gather = read();
String newUser = u.toString();
writer = new PrintWriter(usersFile);
writer.append(gather).append(newUser).append("\n");
writer.close();
System.out.println("The users' file has been updated");
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
}
public static String read(){
String f = null;
try {
read = new Scanner(usersFile);
StringBuilder gather = new StringBuilder();
while(read.hasNext()){
gather.append(read.nextLine()).append("\n");
}
f = gather.toString();
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
return f;
}
public static userObj search(String s){
userObj foundUser = null;
try {
read = new Scanner(usersFile);
String st=null;
while(read.hasNext()){
if (read.next().equalsIgnoreCase(s)){
foundUser = new userObj();
foundUser.name = s;
foundUser.setType(read.next().charAt(0));
foundUser.credit = read.nextDouble();
}
}
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}
return foundUser;
}
public static void remove(userObj u){
String s = u.name;
if (search(s) == null){
return;}
try {
read = new Scanner(usersFile);
StringBuilder gather = new StringBuilder();
while(read.hasNext()){
String info = read.nextLine();
if (info.startsWith(s)){
continue;
}
gather.append(info).append("\n");
}
writer = new PrintWriter(usersFile);
writer.append(gather).append("\n");
writer.close();
System.out.println("The user has been deleted");
}
catch(FileNotFoundException ex){
System.out.print("file not found");
}}
public static void update(userObj u){
remove(u);
write(u);
}
}
You don't need to create "stubs for files", you need to create "stub for reading from an InputStream".
For read, search, and remove you're using Scanner, which accepts an InputStream as one of its overloaded constructors. If you add an InputStream parameter, you can use that to construct your Scanner. With normal use, you can pass a FileInputStream, while using a StringBufferInputStream for testing.
For write and remove you're using a PrintWriter, which accepts an OutputStream as one of its overloaded constructors. If you add an OutputStream parameter, you can use that to construct your PrintWriter. With normal use, you can pass a FileOutputStream, while using a ByteArrayOutputStream for testing. If you want to read the result as a string from your test, use toString(String charsetName).
public class Users {
...
public static void write(UserObj u, InputStream input, OutputStream output) {
...
String gather = read(input);
...
writer = new PrintWriter(output);
...
}
public static String read(InputStream input) {
...
read = new Scanner(input);
...
}
public static UserObj search(String s, InputStream input) {
...
read = new Scanner(input);
...
}
public static void remove(UserObj u, InputStream input, OutputStream output) {
...
read = new Scanner(input);
...
writer = new PrintWriter(output);
...
}
public static void update(UserObj u, InputStream input, OutputStream output) {
remove(u, input, output);
write(u, input, output);
}
}
// Client code example
FileInputStream input = new FileInputStream("usersFile.txt");
FileOutputStream output = new FileOutputStream("usersFile.txt");
...
Users.write(myUser, input, output);
...
String result = Users.read(input);
...
myUser = Users.search(myString, input);
...
Users.remove(myUser, input, output);
...
Users.update(myUser, input, output);
// Testing code example
StringBufferInputStream input = new StringBufferInputStream("...");
ByteArrayOutputStream output = new ByteArrayOutputStream();
...
Users.write(myUser, input, output);
...
String result = Users.read(input);
...
myUser = Users.search(myString, input);
...
Users.remove(myUser, input, output);
...
Users.update(myUser, input, output);
...
result = output.toString("UTF-8"); // see docs for other legal charset names

Redirect System.out.println to log

In my project test suite there is big usage of
System.out.println
I'm trying to redirect these output to log file (through configuration or from single point without refactoring whole project ) so that can be disabled when necessary to improve performance. I'm using log4j for logging.
Does any one know is this possible ? if so how to do it ?
Thanks in advance.
Given that it's better replace the System.out.println(), sometimes we have no choice. Anyway I've made a little utility for that:
SystemOutToSlf4j.enableForClass(MyClass.class)
Then all the println originated from MyClass will be redirected to the logger.
See this post for more details...
public class SystemOutToSlf4j extends PrintStream {
private static final PrintStream originalSystemOut = System.out;
private static SystemOutToSlf4j systemOutToLogger;
/**
* Enable forwarding System.out.println calls to the logger if the stacktrace contains the class parameter
* #param clazz
*/
public static void enableForClass(Class clazz) {
systemOutToLogger = new SystemOutToSlf4j(originalSystemOut, clazz.getName());
System.setOut(systemOutToLogger);
}
/**
* Enable forwarding System.out.println calls to the logger if the stacktrace contains the package parameter
* #param packageToLog
*/
public static void enableForPackage(String packageToLog) {
systemOutToLogger = new SystemOutToSlf4j(originalSystemOut, packageToLog);
System.setOut(systemOutToLogger);
}
/**
* Disable forwarding to the logger resetting the standard output to the console
*/
public static void disable() {
System.setOut(originalSystemOut);
systemOutToLogger = null;
}
private String packageOrClassToLog;
private SystemOutToSlf4j(PrintStream original, String packageOrClassToLog) {
super(original);
this.packageOrClassToLog = packageOrClassToLog;
}
#Override
public void println(String line) {
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
StackTraceElement caller = findCallerToLog(stack);
if (caller == null) {
super.println(line);
return;
}
org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(caller.getClass());
log.info(line);
}
public StackTraceElement findCallerToLog(StackTraceElement[] stack) {
for (StackTraceElement element : stack) {
if (element.getClassName().startsWith(packageOrClassToLog))
return element;
}
return null;
}
}
My suggestion would be to refactor if possible.
For a possible solution, check these similar questions
log4j redirect stdout to DailyRollingFileAppender
Redirect System.out.println to Log4J, while keeping class name information
I think you can use System.setOut(PrintStream) to set your output to a file output stream. Then you can put this line in your BeforeClass method. I like to use a BaseTest class and put this line of code in the beforeclass method of that class. Then make all test cases extend this cclass.
Use shell redirection. Figure out the "java" invocation for your project, if you're on most vaguely UNIX-like systems, ps aux | grep java will help.
Then just run this command with > /path/to/logfile. Example:
java -jar myjar.jar -cp path/to/lib.jar:path/to/otherlib.jar com.bigcorp.myproject.Main > /var/log/myproject.log
public class RecursiveLogging {
public static void main(String[] args) {
System.setOut(new PrintStream(new CustomOutputStream()));
TestMyException.testPrint();
}
}
class CustomOutputStream extends OutputStream {
private Logger logger = Logger.getLogger(this.getClass());
#Override
public final void write(int b) throws IOException {
// the correct way of doing this would be using a buffer
// to store characters until a newline is encountered,
// this implementation is for illustration only
logger.info((char) b);
}
#Override
public void write(byte[] b, int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
byte[] pb = new byte[len];
for (int i = 0 ; i < len ; i++) {
pb[i] = (b[off + i]);
}
String str = new String(pb);
logger.info(str);
}
}
My solution is pretty simple and supports all PrintStream functionality without overloading everything. overloading only flush() as it called by PrintStream methods every new line.
public class ConsoleToLogger
{
private Logger log;
private PrintStream originalStream;
private Level logLevel;
private ByteArrayBufferOutStream buffer;
private PrintStream bufferPrintStream;
ConsoleToLogger(PrintStream realPrintStream, Level pLogLevel)
{
buffer = new ByteArrayBufferOutStream();
bufferPrintStream = new PrintStream(buffer);
originalStream = realPrintStream;
logLevel = pLogLevel;
log = Logger.getLogger(Level.ERROR.equals(pLogLevel) ? "STDERR" : "STDOUT");
}
public PrintStream getPrintStream()
{
return bufferPrintStream;
}
private class ByteArrayBufferOutStream
extends ByteArrayOutputStream
{
#Override
public void flush()
throws IOException
{
super.flush();
String message = buffer.toString();
originalStream.println(message);
log.log(logLevel, message);
buffer.reset();
}
}
}
// assign to System.out and system.err
System.setOut(new ConsoleToLogger(System.out, Level.INFO).getPrintStream());
System.setErr(new ConsoleToLogger(System.err, Level.ERROR).getPrintStream());

Extending OutputStream class; write(int) method

So my goal is to implement the write method in the class OutputStream to create a new class NumStream, which basically converts ints to Strings. Here is my sample code:
import java.io.*;
public class NumStream extends OutputStream {
public void write(int c) throws IOException {
// What goes here?
}
public static void main(String[] args) {
NumStream ns = new NumStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(ns));
pw.println("123456789 and ! and # ");
pw.flush(); // needed for anything to happen, try taking it out
}
}
I've tried using several different approaches, and my result always results in the program compiling, but when I run it, nothing happens. So far I've tried using switch statements to produce this result:
public void write(int c) throws IOException {
StringBuffer sb = new StringBuffer();
switch (c) {
case 1: sb.append("1");
break;
//etc. through 9
I'm unsure of what to do or try next to produce a result. :/ Any tips to steer me in the right direction?
I had the same problem too, Here is the solution:
public class MyOutputStream extends OutputStream {
StringBuilder anotatedText;
public MyOutputStream() {
// Custom constructor
}
#Override
public void write(int b) {
int[] bytes = {b};
write(bytes, 0, bytes.length);
}
public void write(int[] bytes, int offset, int length) {
String s = new String(bytes, offset, length);
anotatedText.append(s);
}
public void myPrint() {
System.out.println(anotatedText);
}
}
All we need to do is to implement the "write" method correctly which is clearly instructed in the above example.

Categories

Resources