I have worked with junit test integration tests and controller tests in spring and usually we test the output of a method but when i tried to test a simple hello world in main method i had no idea how to go about it so will like to get any idea on what do write
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
This is the simple java class any idea how i can test it
I tried to write something like this
public void mainMethodTest() throws Exception{
System.out.println("hello world");
String[] args = null;
Assert.assertEquals(System.out.println("hello world"),App.main(args));
}
You could assign to the System.out variable a ByteArrayOutputStream object which you store the reference in a variable.
Then invoke your main() method and assert that the String content of the ByteArrayOutputStream object contains the expected String:
#Test
public void main() throws Exception{
PrintStream originalOut = System.out; // to have a way to undo the binding with your `ByteArrayOutputStream`
ByteArrayOutputStream bos = new ByteArrayOutputStream();
System.setOut(new PrintStream(bos));
// action
App.main(null);
// assertion
Assert.assertEquals("hello world", bos.toString());
// undo the binding in System
System.setOut(originalOut);
}
Why does it work ?
bos.toString() returns the "Hello World!" String passed in the method under test:
System.out.println( "Hello World!" );
as after setting System.out in this way : System.setOut(new PrintStream(bos));, the out variable refers to a PrintStream object that decorates the ByteArrayOutputStream object referenced by the bos variable.
So any System.out invocations will write bytes in the ByteArrayOutputStream object.
You can change your class this way
import java.io.PrintStream;
public class TestHelloWorld {
public final static void main(String[] args) {
doPrint(System.out);
}
static void doPrint(PrintStream ps) {
ps.println("Hello World");
}
}
and test the doPrint function by providing your own PrintStream you create around a ByteArrayOutputStream:
public void mainMethodTest() throws Exception{
ByteArrayOutputStream data = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(data, true, "UTF-8");
TestHelloWorld.doPrint(ps);
ps.flush();
Assert.assertEquals("Hello World") + System.getProperty("line.separator"), new String(data, "UTF-8"));
}
Another solution is to replace the system's PrintStream by your own:
System.setOut(new PrintStream(data, true, "UTF-8"));
but that's quite ugly and I try to avoid that. Above solution is more clear, easier to maintenance and you can be sure that no other part of a larger application is printing something to STDOUT while you do your test, leading to a failure of it.
You can run Junit from a main method if thats what you mean.
public static void main( String[] args )
{
JUnitCore junit = new JUnitCore();
Result result = null;
try {
result = junit.run(MyTestClass.class);
}
catch(Exception e)
{
e.printStackTrace();
}
int passed = result.getRunCount()-result.getFailureCount();
}
public class MyTestClass{
#Test
public void testAllBrowsers(){
//test code and asserts
}
}
Related
I have the following class:
class Bla {
private static final Consumer<String> OUTPUT = System.out::println;
public void print() {
printStuff(OUTPUT);
}
public void printStuff(Consumer<String> consumer) {
consumer.accept("Bla");
}
}
Test code:
Bla bla = new Bla();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream standardOut = System.out;
System.setOut(new PrintStream(baos));
bla.print();
LOG.info(baos.toString().trim()); <-- This does not work
System.setOut(standardOut);
It logs nothing. Why? When I inline OUTPUT, then it works.
The problem is that when the Bla class initializes, it takes a reference to System.out at that point in time. When you reset System.out in the subsequent code, it has no affect on the value of Bla.OUTPUT.
I think this will do what you want:
OUTPUT = s -> System.out.println(s);
because it will always use the current value of System.out.
I have a Java command-line program. I would like to create JUnit test case to be able to simulate System.in. Because when my program runs it will get into the while loop and waits for input from users. How do I simulate that in JUnit?
Thanks
It is technically possible to switch System.in, but in general, it would be more robust not to call it directly in your code, but add a layer of indirection so the input source is controlled from one point in your application. Exactly how you do that is an implementation detail - the suggestions of dependency injection are fine, but you don't necessarily need to introduce 3rd party frameworks; you could pass round an I/O context from the calling code, for example.
How to switch System.in:
String data = "Hello, World!\r\n";
InputStream stdin = System.in;
try {
System.setIn(new ByteArrayInputStream(data.getBytes()));
Scanner scanner = new Scanner(System.in);
System.out.println(scanner.nextLine());
} finally {
System.setIn(stdin);
}
Based on #McDowell's answer and another answer that shows how to test System.out, I would like to share my solution to give an input to a program and test its output.
As a reference, I use JUnit 4.12.
Let's say we have this program that simply replicates input to output:
import java.util.Scanner;
public class SimpleProgram {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print(scanner.next());
scanner.close();
}
}
To test it, we can use the following class:
import static org.junit.Assert.*;
import java.io.*;
import org.junit.*;
public class SimpleProgramTest {
private final InputStream systemIn = System.in;
private final PrintStream systemOut = System.out;
private ByteArrayInputStream testIn;
private ByteArrayOutputStream testOut;
#Before
public void setUpOutput() {
testOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(testOut));
}
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 testCase1() {
final String testString = "Hello!";
provideInput(testString);
SimpleProgram.main(new String[0]);
assertEquals(testString, getOutput());
}
}
I won't explain much, because I believe the code is readable and I cited my sources.
When JUnit runs testCase1(), it is going to call the helper methods in the order they appear:
setUpOutput(), because of the #Before annotation
provideInput(String data), called from testCase1()
getOutput(), called from testCase1()
restoreSystemInputOutput(), because of the #After annotation
I didn't test System.err because I didn't need it, but it should be easy to implement, similar to testing System.out.
There are a few ways to approach this. The most complete way is to pass in an InputStream while running the class under test which is a fake InputStream which passes simulated data to your class. You can look at a dependency injection framework (such as Google Guice) if you need to do this a lot in your code, but the simple way is:
public class MyClass {
private InputStream systemIn;
public MyClass() {
this(System.in);
}
public MyClass(InputStream in) {
systemIn = in;
}
}
Under test you would call the constructor that takes the input stream. You cloud even make that constructor package private and put the test in the same package, so that other code would not generally consider using it.
Try to refactor your code to use dependency injection. Instead of having your a method that uses System.in directly, have the method accept an InputStream as an argument. Then in your junit test, you'll be able to pass a test InputStream implementation in place of System.in.
You can write a clear test for the command line interface by using the TextFromStandardInputStream rule of the System Rules library.
public void MyTest {
#Rule
public final TextFromStandardInputStream systemInMock
= emptyStandardInputStream();
#Test
public void readTextFromStandardInputStream() {
systemInMock.provideLines("foo");
Scanner scanner = new Scanner(System.in);
assertEquals("foo", scanner.nextLine());
}
}
Full disclosure: I'm the author of that library.
You could create a custom InputStream and attach it to the System class
class FakeInputStream extends InputStream {
public int read() {
return -1;
}
}
And then use it with your Scanner
System.in = new FakeInputStream();
Before:
InputStream in = System.in;
...
Scanner scanner = new Scanner( in );
After:
InputStream in = new FakeInputStream();
...
Scanner scanner = new Scanner( in );
Although I think you should better to test how your class should work with the data read from the input stream and not really how it reads from there.
The problem with BufferedReader.readLine() is that it is a blocking method which waits for user input. It seems to me that you don't particularly want to simulate that (i.e. you want tests to be fast). But in a testing context it continually returns null at high speed during testing, which is irksome.
For a purist you can make the getInputLine below package-private, and mock it: easy-peezy.
String getInputLine() throws Exception {
return br.readLine();
}
... you'd have to make sure that you had a way of stopping (typically) a loop of user interaction with the app. You'd also have to cope with the fact that your "input lines" would always be the same until you somehow changed the doReturn of your mock: hardly typical of user input.
For a non-purist who wishes to make life easy for themselves (and produce readable tests) you could put all this stuff below in your app code:
private Deque<String> inputLinesDeque;
void setInputLines(List<String> inputLines) {
inputLinesDeque = new ArrayDeque<String>(inputLines);
}
private String getInputLine() throws Exception {
if (inputLinesDeque == null) {
// ... i.e. normal case, during app run: this is then a blocking method
return br.readLine();
}
String nextLine = null;
try {
nextLine = inputLinesDeque.pop();
} catch (NoSuchElementException e) {
// when the Deque runs dry the line returned is a "poison pill",
// signalling to the caller method that the input is finished
return "q";
}
return nextLine;
}
... in your test you might then go like this:
consoleHandler.setInputLines( Arrays.asList( new String[]{ "first input line", "second input line" }));
before triggering off the method in this "ConsoleHandler" class which needs input lines.
maybe like this (not tested):
InputStream save_in=System.in;final PipedOutputStream in = new PipedOutputStream(); System.setIn(new PipedInputStream(in));
in.write("text".getBytes("utf-8"));
System.setIn( save_in );
more parts:
//PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));
InputStream save_in=System.in;final PipedOutputStream in = new PipedOutputStream(); System.setIn(new PipedInputStream(in));
//start something that reads stdin probably in a new thread
// Thread thread=new Thread(new Runnable() {
// #Override
// public void run() {
// CoursesApiApp.main(new String[]{});
// }
// });
// thread.start();
//maybe wait or read the output
// for(int limit=0; limit<60 && not_ready ; limit++)
// {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// }
in.write("text".getBytes("utf-8"));
System.setIn( save_in );
//System.setOut(save_out);
#Stefan Birkner, Thanks!
Modify Pom.xml
Ref:
https://stackoverflow.com/a/66127606/8317677
https://github.com/stefanbirkner/system-lambda/blob/master/pom.xml
https://github.com/stefanbirkner/system-lambda/blob/master/src/test/java/com/github/stefanbirkner/systemlambda/WithTextFromSystemInTest.java
<properties>
<system-lambda.version>1.2.1</system-lambda.version>
</properties>
<dependencies>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>${system-lambda.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
Add function code
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class SimpleProgram003 {
public static void main(String[] args) {
try{
String c;
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
do{
c = in.readLine();
System.out.println(c);
String d = c;
}while(!c.equals("q"));
}catch(Exception e){
System.out.println("catch Exception");
}
}
}
Add test code
import static com.github.stefanbirkner.systemlambda.SystemLambda.*;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintStream;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Unit test for simple App. JUnit 4.x.
*/
public class SimpleProgram003Test {
private final InputStream systemIn = System.in;
private final PrintStream systemOut = System.out;
private ByteArrayInputStream testIn;
private ByteArrayOutputStream testOut;
#Before
public void setUpOutput() {
testOut = new ByteArrayOutputStream();
System.setOut(new PrintStream(testOut));
}
private void setInput(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 testCase1() {
final String testString = "Hello 1\nq\n";
setInput(testString);
SimpleProgram003.main(new String[0]);
// String a = getOutput();
assertEquals("Hello 1\r\nq\r\n", getOutput());
}
#Test // Multiply inputs
public void testCase2() throws Exception {
withTextFromSystemIn(
"Input1",
"Input2",
"q",
"Input3"
).execute(() -> {
SimpleProgram003.main(new String[0]);
// String a = getOutput();
assertEquals("Input1\r\nInput2\r\nq\r\n", getOutput());
});
}
}
I have an AWS Lambda implemented in java. The lambda generates a file, then writes it to the output, using the Base64 encoder. I'm trying to write a unit test for it, but it enters an infinite loop when the file is written.
What I'd like to do is capture what is written to the encodedStream in the unit test, write it to the temporary folder, and then compare the contents to the expected contents, but the test hangs until eventually an out of memory exception is thrown.
Lambda code
public class MyLambda implements RequestStreamHandler {
private static final Logger LOGGER = LogManager.getLogger(MyLambda.class);
#Override
public void handleRequest(#Nonnull InputStream inputStream, #Nonnull OutputStream outputStream, #Nonnull Context context) {
try (OutputStream encodedStream = Base64.getEncoder().wrap(outputStream);){
encodedStream.write("This is written to file".getBytes());
} catch (IOException e) {
LOGGER.info("IOException occurred ", e);
}
}
}
Unit test
public class MyLambdaTest {
#Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
#Test
public void testRequest() throws IOException {
MyLambda myLambda = new MyLambda();
InputStream inputStream = mock(InputStream.class);
OutputStream mockOutputStream = mock(OutputStream.class);
Context mockContext = mock(Context.class);
doNothing().when(mockOutputStream).write(anyInt());
doNothing().when(mockOutputStream).write(any(byte[].class));
doNothing().when(mockOutputStream).write(any(byte[].class), anyInt(), anyInt());
myLambda.handleRequest(inputStream, mockOutputStream, mockContext);
FileUtils.writeByteArrayToFile(temporaryFolder.newFile(), <captured bytes>);
}
}
I have deployed the code to AWS, so I know it works, but I'd like to have a proper unit test written for it for future builds
Instead of mocking the OutputStream, you can create a ByteArrayOutputStream. It's basically just an array of bytes that implements OutputStream. And then you can verify the correct content was written with ByteArrayOutputSteam#toBytes(), or ByteArrayOutputStream#toString()
FileOutputStream fout =
new FileOutputStream(temporaryFolder.newFile("testout.txt"));
MyLambda myLambda = new MyLambda();
myLambda.handleRequest(null, fout, null);
fout.close();
Hi Joseph,
Please find my attempt above. I have used a real FileOutputStream.
easy question is there an other function i can use instead of println, because i want to output a non-static variable to a file usig out.println();
This is my code:
import java.io.*;
public class main {
String outputString ="Math.sqrt(25);" ;
static String outputPath ="src/output.txt";
/**
* #param args
*/
public static void main(String[] args) throws IOException {
File f;
f= new File (outputPath);
//file creation
if(!f.exists()){
f.createNewFile();
System.out.println("File has been created");
}else{
f.delete();
System.out.println("1. File has been deleted");
f.createNewFile();
System.out.println("2. File has been created");
}
//adding string(text) to file
try{
FileWriter outFile = new FileWriter(args[0]);
PrintWriter out = new PrintWriter(outFile);
out.println(outputString);
out.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
if that is not posible maybe there is an whole other way to go around it. my main problem is that i want to make a string in to peace of code. But that seem to be hard to do :) any help on that :)
The problem has nothing to do with println(). It has to do with the fact that, being non-static, outputString is associated with an instance of your class, and your code creates no such instance.
Either make outputString static, or create an instance of main:
public void doit(String[] args) throws IOException {
...
PrintWriter out = ...;
out.println(outputString);
...
}
public static void main(String[] args) throws IOException {
new main().doit(args);
}
The println function can print both static and non-static variables. The problem is that you're trying to access a non-static variable outputString from within a static context (your main method).
println is a non-static method of the PrintStream class. System, also a class, has a static member called out of type PrintStream which you can retrieve via the System.out call. This member is initialized when java is started.
Note that this does not in any way imply that this is anything other than a regular Object of type PrintStream, it's just that it's a singleton that is conveniently accessible statically from System.
I'm trying to learn the ins and outs of various mocking libraries and PowerMock(specifically the EasyMock extension) is next on the list. I'm attempting to mock a constructor and the examples provided don't have the same response when I try to replicate them. As far as I can tell, it never mocks the constructor and just proceeds as if it were normal.
This is the test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Writer.class})
public class FaultInjectionSituationTest {
#Test
public void testActionFail() throws Exception {
FaultInjectionSituation fis = new FaultInjectionSituation();
PowerMock.expectNew(Writer.class, "test")
.andThrow(new IOException("thrown from mock"));
PowerMock.replay(Writer.class);
System.out.println(fis.action());
PowerMock.verify(Writer.class);
}
}
I've tried replacing the "test" with an EasyMock.isA(String.class), but it yielded the same results.
This is the FaultInjectionSituation:
public class FaultInjectionSituation {
public String action(){
Writer w;
try {
w = new Writer("test");
} catch (IOException e) {
System.out.println("thrown: " + e.getMessage());
return e.getLocalizedMessage();
}
return "returned without throw";
}
}
The "Writer" is nothing more than a shell of a class:
public class Writer {
public Writer(String s) throws IOException {
}
public Writer() throws IOException{
}
}
When the test is run, it prints out "returned without throw", indicating the exception was never thrown.
You need to prepare the class that is calling the constructor as well, so PowerMock knows to expect a mocked constructor call. Try updating your code with the following:
#RunWith(PowerMockRunner.class)
#PrepareForTest({Writer.class, FaultInjectionSituation.class})
public class FaultInjectionSituationTest {
// as before
}
You need to first create a mock object:
Writer mockWriter = PowerMock.createMock(Writer.class)
PowerMock.expectNew(Writer.class, "test").andReturn(mockWriter)