I am currently dead in the water with a Java programming problem that seemed somewhat simple at first to do! I am trying to write text to a file from MULTIPLE methods in a class that does NOT contain a main() method, unlike other answers of this type question have used.
So... A quick outline of what my program is currently doing:
My program has one class (with the main() method obviously) that reads a text file stored on the disk, and passes sections of the text to certain methods in another class (second file in the project) to simply write the passed text to a text file. Each method in the class without the main() method needs to write the string passed to them to THE SAME file.
Why am I having trouble? I can easily write text to a file from ONE method in the class without the main() with FileWriter, but in order to have all of my other methods to write to the same file, I would need to make FileWriter global. I have tried to make it global, but then when I save text after another method saved text, it just rewrites the file to the latest text written.
My current class without the main() method:
package ADIFTOCSV;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class createADIF {
static File file;
static FileWriter fw;
static BufferedWriter writer;
static void init() throws IOException {
file = new File("/Users/Colin/Desktop/Myadif.txt");
fw = new FileWriter(file.getAbsoluteFile());
writer = new BufferedWriter(fw);
}
static void storeDate(String datez) throws IOException {
writer.write("<QSO_DATE:" + datez.length() + ">" + datez); <<----NULL POINTER EXCEPTION
}
static void storeFreq(String freqz) throws IOException {
writer.write("<FREQ:" + freqz.length() + ">" + freqz);
writer.close();
}
static void storeMode(String modez) {
}
static void storeBand(String bandz) {
}
static void storePower(String pwrz) {
}
static void storeTime(String timez) {
}
static void storeCall(String callz) {
}
static void storeRstSent(String rstsentz) {
}
static void storeRstRcvd(String rstrcvdz) {
}
static void storeComments(String commentsz) {
}
}
Each of these methods needs to write the String passed to them to the SAME file.
storeDate() is the first method to be called, therefore it writes text to the file first. However, when storeFreq() is called, it's text completely replaces the text written by storeDate(). This is obvious because I am forced to create a new FileWriter object in each method in order to write text. I cannot put FileWriter fw = new FileWriter(file.getAbsoluteFile()); outside the method to make it global; errors arise.
Am I missing something? Help is much appreciated. If any questions arise, or clarification is needed, please just ask!
You have to create the writer outside the methods.
Just defining the file outside is not enough.
If you recreate a writer to the same file in each method, of course it will overwrite.
The File instance is just a pointer to the file.
The writer is the "actual handle" that you need to reuse.
And be aware that you have to close the writer if you are finished with writing.
I would suggest that you scrap the class with the static methods and instead create a normal "File Write Handler" class which has a constructor where you can pass the File and writer to intialize the file writing classes and let that class handle all the writing to the file such that you can call a method like this:
FileWriteHandler.writer("<FREQ:" + freqz.length() + ">" + freqz);
and soforth for the rest you want printed. And finally call
FileWriteHandler.close();
Would be much cleaner and you could even make an interface for that class such that you can replace the FileWriterHandler with f.ex. a DatabaseWriteHandler or something like that.
I have problem mock whenNew(File.class) using PowerMockito. Here is my method I want to test:
public void foo() {
File tmpFile = new File("Folder");
if (!tmpFile.exists()) {
if (!configFolder.mkdir()) {
throw new RuntimeException("Can't create folder");
}
}
File oneFileInFolder = new File(tmpFile, "fileOne.txt");
if (oneFileInFolder.exists()){
//do something
}
}
Here is test code I wrote:
static File mockFile;
#Before
public void setUp() throws Exception {
//....some code
mockFolder = mock(File.class);
when(mockFolder.getPath()).thenReturn("Folder");
when(mockFolder.exists()).thenReturn(true);
whenNew(File.class).withParameterTypes(String.class).withArguments(anyString()).thenReturn(mockFolder);
//...some code
}
But when I debug my testcase, I still see a real folder created in my pwd. I don't want folders created when I run my testcases. Any idea?
Since you haven't specified this in your question, the following may be missing:
#PrepareForTest(ClassYoureCreatingTheFileInstanceIn.class)
According to the Wiki:
Note that you must prepare the class creating the new instance of MyClass for test, not the MyClass itself. E.g. if the class doing new MyClass() is called X then you'd have to do #PrepareForTest(X.class) in order for whenNew to work.
In other words, X is the class that contains foo() in your example.
I am newbie to Java and facing below issue. I have following code:
public class ReadExcel {
Config conf = new Config();
String filePath = conf.getInputfilePath();
#Test
public void readFullXL() {
try {
FileInputStream FSRead = new FileInputStream(filePath);
I have declared this variable ‘filePath’ outside function because; I want to use it as global variable.
However, inside readFullXL(), I am not able to get value for variable ‘filePath’ and getting null pointer exception.
Can somebody suggest? How I can declare global variable in Junit file.
Edit:
Of course first you gotta check that your getInputfilePath() method does not return null.
Further: I suggest you go ahead and read some informations on UnitTesting (JUnit - Tutorial).
If it's just one test you could just instantiate your needed classes within that test.
#Test
public void readFullXL() {
Config conf = new Config();
FileInputStream FSRead = new FileInputStream(conf.getInputfilePath());
//...
}
If you have multiple tests relying on the same fixture you can go ahead and implement a setup method using the #Before annotation. The setup method will then be called before every test (#Test annotation) method.
class ReadExcel {
Config conf;
#Before
public void setUp() {
conf = new Config();
}
#Test
public void readFullXL() {
//...
FileInputStream FSRead = new FileInputStream(conf.getInputfilePath());
// Run your test
}
}
Thank you for your response and time.
I got it working by creating interface between config and ReadExcel file.
Also removed Junit test annotation from config file that was not required.
Thanks,
Ashvini
I have an application where I want to write unit tests to test the output, written to System.out (and perhaps System.err).
Each individual test works as expected, however when adding multiple tests in the same class some tests fail because JUnit4 appears to be multi-threaded (thus no guarantees exists on when exactly the stream is reset).
The same happens when I separate all test methods in their own class and use a test suite.
Any ideas?
private static final PrintStream SYS_OUT = System.out;
private static final PrintStream SYS_ERR = System.err;
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
#Before
public final void setUpStreams() throws UnsupportedEncodingException {
System.setOut(new PrintStream(this.outContent, true, CHARSET));
System.setErr(new PrintStream(this.errContent, true, CHARSET));
}
#After
public final void cleanUpStreams() {
System.setOut(SYS_OUT);
System.setErr(SYS_ERR);
}
#Test
public final void listServicesAndMethods() throws ServiceException, UnsupportedEncodingException {
com.example.Main.main(new String[]{"--list-services"});
LOG.debug(this.outContent.toString(CHARSET));
assertTrue("String not found", this.outContent.toString(CHARSET).contains("Some string"));
assertFalse("Other string found", this.outContent.toString(CHARSET).contains("Some other string"));
this.outContent.reset();
this.errContent.reset();
}
Edit: It turns out that the issue with the failing tests was not (just?) because of the streams, but due to the fact that I stored the options in static fields in my main class. This has the effect that several options stay active during consecutive tests. I realised that after implementing Arian's suggestion, I then used the second class as an instance, instead of calling static methods, thus solving my issue.
Thanks to all who replied.
If not already done so, rewrite the parts of your application to take the output as a parameter, instead of writing directly to System.out. This is usually better design regardless of testing.
In each test, create a new output stream (or spy on System.out if you must) and pass it to the code unit under test.
I need to write JUnit tests for an old application that's poorly designed and is writing a lot of error messages to standard output. When the getResponse(String request) method behaves correctly it returns a XML response:
#BeforeClass
public static void setUpClass() throws Exception {
Properties queries = loadPropertiesFile("requests.properties");
Properties responses = loadPropertiesFile("responses.properties");
instance = new ResponseGenerator(queries, responses);
}
#Test
public void testGetResponse() {
String request = "<some>request</some>";
String expResult = "<some>response</some>";
String result = instance.getResponse(request);
assertEquals(expResult, result);
}
But when it gets malformed XML or does not understand the request it returns null and writes some stuff to standard output.
Is there any way to assert console output in JUnit? To catch cases like:
System.out.println("match found: " + strExpr);
System.out.println("xml not well formed: " + e.getMessage());
using ByteArrayOutputStream and System.setXXX is simple:
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
private final PrintStream originalErr = System.err;
#Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
#After
public void restoreStreams() {
System.setOut(originalOut);
System.setErr(originalErr);
}
sample test cases:
#Test
public void out() {
System.out.print("hello");
assertEquals("hello", outContent.toString());
}
#Test
public void err() {
System.err.print("hello again");
assertEquals("hello again", errContent.toString());
}
I used this code to test the command line option (asserting that -version outputs the version string, etc etc)
Edit:
Prior versions of this answer called System.setOut(null) after the tests; This is the cause of NullPointerExceptions commenters refer to.
I know this is an old thread, but there is a nice library to do this: System Rules
Example from the docs:
public void MyTest {
#Rule
public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
#Test
public void overrideProperty() {
System.out.print("hello world");
assertEquals("hello world", systemOutRule.getLog());
}
}
It will also allow you to trap System.exit(-1) and other things that a command line tool would need to be tested for.
Instead of redirecting System.out, I would refactor the class that uses System.out.println() by passing a PrintStream as a collaborator and then using System.out in production and a Test Spy in the test. That is, use Dependency Injection to eliminate the direct use of the standard output stream.
In Production
ConsoleWriter writer = new ConsoleWriter(System.out));
In the Test
ByteArrayOutputStream outSpy = new ByteArrayOutputStream();
ConsoleWriter writer = new ConsoleWriter(new PrintStream(outSpy));
writer.printSomething();
assertThat(outSpy.toString(), is("expected output"));
Discussion
This way the class under test becomes testable by a simple refactoring, without having the need for indirect redirection of the standard output or obscure interception with a system rule.
You can set the System.out print stream via setOut() (and for in and err). Can you redirect this to a print stream that records to a string, and then inspect that ? That would appear to be the simplest mechanism.
(I would advocate, at some stage, convert the app to some logging framework - but I suspect you already are aware of this!)
Slightly off topic, but in case some people (like me, when I first found this thread) might be interested in capturing log output via SLF4J, commons-testing's JUnit #Rule might help:
public class FooTest {
#Rule
public final ExpectedLogs logs = new ExpectedLogs() {{
captureFor(Foo.class, LogLevel.WARN);
}};
#Test
public void barShouldLogWarning() {
assertThat(logs.isEmpty(), is(true)); // Nothing captured yet.
// Logic using the class you are capturing logs for:
Foo foo = new Foo();
assertThat(foo.bar(), is(not(nullValue())));
// Assert content of the captured logs:
assertThat(logs.isEmpty(), is(false));
assertThat(logs.contains("Your warning message here"), is(true));
}
}
Disclaimer:
I developed this library since I could not find any suitable solution for my own needs.
Only bindings for log4j, log4j2 and logback are available at the moment, but I am happy to add more.
If you were using Spring Boot (you mentioned that you're working with an old application, so you probably aren't but it might be of use to others), then you could use org.springframework.boot.test.rule.OutputCapture in the following manner:
#Rule
public OutputCapture outputCapture = new OutputCapture();
#Test
public void out() {
System.out.print("hello");
assertEquals(outputCapture.toString(), "hello");
}
#dfa answer is great, so I took it a step farther to make it possible to test blocks of ouput.
First I created TestHelper with a method captureOutput that accepts the annoymous class CaptureTest. The captureOutput method does the work of setting and tearing down the output streams. When the implementation of CaptureOutput's test method is called, it has access to the output generate for the test block.
Source for TestHelper:
public class TestHelper {
public static void captureOutput( CaptureTest test ) throws Exception {
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
ByteArrayOutputStream errContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
test.test( outContent, errContent );
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out)));
System.setErr(new PrintStream(new FileOutputStream(FileDescriptor.out)));
}
}
abstract class CaptureTest {
public abstract void test( ByteArrayOutputStream outContent, ByteArrayOutputStream errContent ) throws Exception;
}
Note that TestHelper and CaptureTest are defined in the same file.
Then in your test, you can import the static captureOutput. Here is an example using JUnit:
// imports for junit
import static package.to.TestHelper.*;
public class SimpleTest {
#Test
public void testOutput() throws Exception {
captureOutput( new CaptureTest() {
#Override
public void test(ByteArrayOutputStream outContent, ByteArrayOutputStream errContent) throws Exception {
// code that writes to System.out
assertEquals( "the expected output\n", outContent.toString() );
}
});
}
Based on #dfa's answer and another answer that shows how to test System.in, 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.
Full JUnit 5 example to test System.out (replace the when part):
package learning;
import static org.assertj.core.api.BDDAssertions.then;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class SystemOutLT {
private PrintStream originalSystemOut;
private ByteArrayOutputStream systemOutContent;
#BeforeEach
void redirectSystemOutStream() {
originalSystemOut = System.out;
// given
systemOutContent = new ByteArrayOutputStream();
System.setOut(new PrintStream(systemOutContent));
}
#AfterEach
void restoreSystemOutStream() {
System.setOut(originalSystemOut);
}
#Test
void shouldPrintToSystemOut() {
// when
System.out.println("example");
then(systemOutContent.toString()).containsIgnoringCase("example");
}
}
You don't want to redirect the system.out stream because that redirects for the ENTIRE JVM. Anything else running on the JVM can get messed up. There are better ways to test input/output. Look into stubs/mocks.
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.
// 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());
for out
#Test
void it_prints_out() {
PrintStream save_out=System.out;final ByteArrayOutputStream out = new ByteArrayOutputStream();System.setOut(new PrintStream(out));
System.out.println("Hello World!");
assertEquals("Hello World!\r\n", out.toString());
System.setOut(save_out);
}
for err
#Test
void it_prints_err() {
PrintStream save_err=System.err;final ByteArrayOutputStream err= new ByteArrayOutputStream();System.setErr(new PrintStream(err));
System.err.println("Hello World!");
assertEquals("Hello World!\r\n", err.toString());
System.setErr(save_err);
}
Although this question is very old and has already very good answers I want to provide an alternative. I liked the answer of dfa however I wanted to have something reusable in different projects without copying the configuration and so I created a library out of it and wanted to contribute back to the community. 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();
}
}
You cannot directly print by using system.out.println or using logger api while using JUnit. But if you want to check any values then you simply can use
Assert.assertEquals("value", str);
It will throw below assertion error:
java.lang.AssertionError: expected [21.92] but found [value]
Your value should be 21.92, Now if you will test using this value like below your test case will pass.
Assert.assertEquals(21.92, str);