Functional test in java, explanation - java

This is a sample program:
public class FunctionalTest {
public int f(int r) {
int result = r * 5;
return result;
}
public static void main(String[] args) {
FunctionalTest funct = new FunctionalTest();
System.out.println(funct.f(5));
}
}
I'm a beginner.
How to write a functional test for this code?
How to write functional tests? Do I need to TestNG?
Is it enough to write the examination method?
Could someone explain to me and write a sample functional test for this program?

Well, if you're specifically asking for functional testing, there's not much you can do with that code snippet. You can do a unit test from the f method using JUnit like this:
#Test
public void testF(){
FunctionalTest t1 = new FunctionalTest();
assertEquals((t1.f(1) % 5), 0); //checks that is getting multiplied by 5.
}
However, you want functional testing, so by running your compiled app and assessing the result you're testing your app functionality by multiple units (AKA integration): your f method and your main method.
Regards!

First of all, you need to have a clear definition of contract you want to verify. From the code, I assume it is something like "the method should return the number equal to argument multiplied by 5".
TestNG, JUnit or other test frameworks is not mandatory for your case. The test may look like:
public void testF() {
int arg = 5;
int result = new FunctionalTest().f(arg);
assert result == arg * 5;
}
Also please keep in mind that to use assert you need JVM started with -ea flag.

Beware the terms you used:
the functional testing provide values to your user/customer
That implies:
black box testing: you have to test your whole system (hard+soft)
the test should target your user/customer needs (explicit report or test)
You can use whatever you want to test the feature (from unit test to jbehave).
In your case (using JUnit 4 and AssertJ):
import org.assertj.core.api.Assertions;
import org.junit.Test;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/*
As an user
I want have 25 whatever I sent
*/
public class NumberGenerationTest {
private static final String PATH = "directory of your class file";
private InputStream stdout;
/* Nominal case */
#Test
public void shall_return_number_25_when_called_with_5() throws Exception {
when_I_call_FunctionalTest_with("5");
then_it_returns("25");
}
/* Nominal case or potential error case */
#Test
public void shall_return_number_25_when_called_with_10() throws Exception {
when_I_call_FunctionalTest_with("10");
then_it_returns("25");
}
/* Nominal case or potential error case */
#Test
public void shall_return_number_25_when_called_with_ABC() throws Exception {
when_I_call_FunctionalTest_with("ABC");
then_it_returns("25");
}
private void when_I_call_FunctionalTest_with(String parameter) throws Exception {
ProcessBuilder builder = new ProcessBuilder("java" ,"-classpath", PATH,"FunctionalTest" , parameter);
builder.redirectErrorStream(true);
Process process = builder.start();
stdout = process.getInputStream ();
}
private void then_it_returns(String expectedResult) throws Exception {
BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
String line = reader.readLine ();
Assertions.assertThat(line).isNotNull();
Assertions.assertThat(line).isEqualTo(expectedResult);
}
}
It seems you have an error in your main() ... or not.

Related

How to automation testing with a Console Application with already test cases set

I just complete a Java CONSOLE application for Student Management.
I received a test case set (pdf file contains lines follow according to the requirements of the application) build based on the standard program (from my lecturer). You can overview what my app do and what is format of test casenter image description heree set in the attached image below.
The problem is that I want to use test cases for testing my app but instead of manually entering and matching line by line between Console IO and the pdf file => I want to write a program to automatically import and match the data between my jar/program to test cases.
However, I'm not sure how and where to start.
I have tried with google but unit test/white testing is still the thing that takes up all of my search. Hopefully in the process of continuing to try to search with google, someone will give me some suggestions or directions that will be useful to me. Thanks very much.
[My Program]
[Test cases set]
The way I'd do it is to decouple your application from the console so that you can use fake implementations for printing and reading from the console in your tests. "Fake" is the technical term - you can look up "test doubles" to learn about those and other related ideas. This idea is known as dependency injection, or the dependency inversion principle.
The way we do this is to use interfaces. Here's an example of an application that prints some items:
import java.util.List;
public class ItemPrinterApplication {
public ItemPrinterApplication(OutputWriter outputWriter, List<Item> items) {
this.outputWriter = outputWriter;
this.items = items;
}
public void run() {
outputWriter.writeLine("Name, Price");
items.forEach(item -> outputWriter.writeLine(item.name + ", " + item.price));
}
private OutputWriter outputWriter;
private List<Item> items;
}
OutputWriter is the thing responsible for the printing. It's just an interface, so the application doesn't know whether it writes to the console or somewhere else:
public interface OutputWriter {
void writeLine(String line);
}
For completeness, the Item class just holds some data:
public class Item {
public Item(String name, Integer price) {
this.name = name;
this.price = price;
}
public final String name;
public final Integer price;
}
I can then write a test using JUnit that checks that when I run this application, I get the output that I want. I do that by using an implementation of OutputWriter that just writes to a string. That way it's easy to check in the test:
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
public class ItemPrinterTest {
#Test
public void itPrintsAListOfItems() {
List<Item> items =
List.of(
new Item("Apple", 50),
new Item("Carrot", 25),
new Item("Milk", 120)
);
FakeOutputWriter fakeOutputWriter = new FakeOutputWriter();
ItemPrinterApplication app = new ItemPrinterApplication(fakeOutputWriter, items);
app.run();
Assertions.assertEquals(
"Name, Price\n" +
"Apple, 50\n" +
"Carrot, 25\n" +
"Milk, 120\n",
fakeOutputWriter.written
);
}
}
and FakeOutputWriter looks like
public class FakeOutputWriter implements OutputWriter {
public String written = "";
#Override
public void writeLine(String line) {
written += line;
written += "\n";
}
}
This gives me confidence that I'm writing the output correctly. In main, though, I want to actually print to the console:
import java.util.List;
public class Main {
public static void main(String[] args) {
OutputWriter outputWriter = new ConsoleOutputWriter();
List<Item> items =
List.of(
new Item("Apple", 50),
new Item("Carrot", 25),
new Item("Milk", 120)
);
new ItemPrinterApplication(outputWriter, items).run();
}
}
and ConsoleOutputWriter does exactly that:
public class ConsoleOutputWriter implements OutputWriter{
#Override
public void writeLine(String line) {
System.out.println(line);
}
}
You could take the same approach for faking reading input. Your interface would have a function that takes no arguments and reads a string:
interface InputReader {
String readLine()
}
so in the tests you could fake that and in main, read using a Scanner or something.

Cucumber Java: How to force JSON plugin generation

Overview: There are instances where in I want to stop the running cucumber test pack midway -- say for example when x number of tests failed.
I can do this just fine but I want the json file (plugin = {json:...}) to be generated when the test stops. Is this doable?
What I've tried so far:
Debug and see where the reporting / plugin generation happens. It seems to be when this line executes:
Cucumber.java: runtime.getEventBus().send.....
#Override
protected Statement childrenInvoker(RunNotifier notifier) {
final Statement features = super.childrenInvoker(notifier);
return new Statement() {
#Override
public void evaluate() throws Throwable {
features.evaluate();
runtime.getEventBus().send(new TestRunFinished(runtime.getEventBus().getTime()));
runtime.printSummary();
}
};
}
I was hoping to access the runtime field but it has a private modifier. I also tried accessing it via reflections but I'm not exactly getting what I need.
Found a quite dirty, but working solution and got what I need. Posting my solution here in case anyone might need.
Create a custom cucumber runner implementation to take the runtime instance.
public final class Foo extends Cucumber {
static Runtime runtime;
/**
* Constructor called by JUnit.
*
* #param clazz the class with the #RunWith annotation.
* #throws IOException if there is a problem
* #throws InitializationError if there is another problem
*/
public Foo(Class clazz) throws InitializationError, IOException {
super(clazz);
}
#Override
protected Runtime createRuntime(ResourceLoader resourceLoader, ClassLoader classLoader, RuntimeOptions runtimeOptions) throws InitializationError, IOException {
runtime = super.createRuntime(resourceLoader, classLoader, runtimeOptions);
return runtime;
}
}
Call the same line that generates the file depending on the plugin used:
public final class ParentHook {
#Before
public void beforeScenario(Scenario myScenario) {
}
#After
public void afterScenario() {
if (your condition to stop the test) {
//custom handle to stop the test
myHandler.pleaseStop();
Foo.runtime.getEventBus().send(new TestRunFinished(Foo.runtime.getEventBus().getTime()));
}
}
}
This will however require you to run your test via Foo.class eg:
#RunWith(Foo.class) instead of #RunWith(Cucumber.class)
Not so much value here but it fits what I need at the moment. I hope Cucumber provides a way to do this out of the box. If there's a better way, please do post it here so I can accept your answer once verified.
Why not quit?
import cucumber.api.Scenario;
import cucumber.api.java.After;
import cucumber.api.java.Before;
import cucumber.api.java.en.When;
public class StepDefinitions {
private static int failureCount = 0;
private int threshold = 20;
#When("^something$")
public void do_something() {
// something
}
#After
public void after(Scenario s) {
if (s.isFailed()) ++failureCount;
}
#Before
public void before() {
if (failureCount > threshold) {
if (driver !=null) {
driver.quit();
driver = null;
}
}
}

Is there a way to make Eclipse run a JUnit test multiple times until failure?

We occasionally have bugs that appear once in every X runs. Before people check in stuff (where it is automatically JUnit'd), our devs need to pass JUnit locally via Eclipse.
Is there some convenient way (built in or high-quality Plugin) to make Eclipse run the same test X times and stop if there's a failure? An alternative to just clicking Run X times?
Note that I'm looking for something in the UI (e.g., right click and say "Run X times" instead of just "Run").
If the for loop works, then I agree with nos.
If you need to repeat the entire setup-test-teardown, then you can use a TestSuite:
Right-click on the package containing the test to repeat
Go to New and choose to create a JUnit test SUITE
Make sure that only the test you want to repeat is selected and click through to finish.
Edit the file to run it multiple times.
In the file you just find the
addTestSuite(YourTestClass.class)
line, and wrap that in a for loop.
I'm pretty sure that you can use addTest instead of addTestSuite to get it to only run one test from that class if you just want to repeat a single test method.
If you really want to run a test class until failure, you need your own runner.
#RunWith(RunUntilFailure.class)
public class YourClass {
// ....
}
which could be implemented as follows...
package com.example;
import org.junit.internal.runners.*;
import org.junit.runner.notification.*;
import org.junit.runner.*;
public class RunUntilFailure extends Runner {
private TestClassRunner runner;
public RunUntilFailure(Class<?> klass) throws InitializationError {
this.runner = new TestClassRunner(klass);
}
#Override
public Description getDescription() {
Description description = Description.createSuiteDescription("Run until failure");
description.addChild(runner.getDescription());
return description;
}
#Override
public void run(RunNotifier notifier) {
class L extends RunListener {
boolean fail = false;
public void testFailure(Failure failure) throws Exception { fail = true; }
}
L listener = new L();
notifier.addListener(listener);
while (!listener.fail) runner.run(notifier);
}
}
...releasing untested code, feeling TDD guilt :)
Based on #akuhn's answer, here is what I came up with - rather than running forever, this will run 50 times or until failure, whichever comes first.
package com.foo
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class RunManyTimesUntilFailure extends Runner {
private static final int MAX_RUN_COUNT = 50;
private BlockJUnit4ClassRunner runner;
#SuppressWarnings("unchecked")
public RunManyTimesUntilFailure(final Class testClass) throws InitializationError {
runner = new BlockJUnit4ClassRunner(testClass);
}
#Override
public Description getDescription() {
final Description description = Description.createSuiteDescription("Run many times until failure");
description.addChild(runner.getDescription());
return description;
}
#Override
public void run(final RunNotifier notifier) {
class L extends RunListener {
boolean shouldContinue = true;
int runCount = 0;
#Override
public void testFailure(#SuppressWarnings("unused") final Failure failure) throws Exception {
shouldContinue = false;
}
#Override
public void testFinished(#SuppressWarnings("unused") Description description) throws Exception {
runCount++;
shouldContinue = (shouldContinue && runCount < MAX_RUN_COUNT);
}
}
final L listener = new L();
notifier.addListener(listener);
while (listener.shouldContinue) {
runner.run(notifier);
}
}
}
I know it doesn't answer the question directly but if a test isn't passing every time it is run it is a test smell known as Erratic Test. There are several possible causes for this (from xUnit Test Patterns):
Interacting Tests
Interacting Test Suites
Lonely Test
Resource Leakage
Resource Optimism
Unrepeatable Test
Test Run War
Nondeterministic Test
The details of each of these is documented in Chapter 16 of xUnit Test Patterns.
Here is a post I wrote that shows several ways of running the tests repeatedly with code examples:
http://codehowtos.blogspot.com/2011/04/run-junit-test-repeatedly.html
You can use the #Parametrized runner, or use the special runner included in the post
There is also a reference to a #Retry implementation
I don't believe there's a built in way for junit to do exactly what you're asking for.
If multiple runs produce different result, you should have a unit test testing that case. Wich might be as simple as running a for loop in the relevant test cases.
It is possible to implement such an loop with TestRules (since JUnit 4.9)
A very simple implementation that runs every Test 10 times:
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class SimpleRepeatRule implements TestRule {
private static class SimpleRepeatStatement extends Statement {
private final Statement statement;
private SimpleRepeatStatement(Statement statement) {
this.statement = statement;
}
#Override
public void evaluate() throws Throwable {
for (int i = 0; i < 10; i++) {
statement.evaluate();
}
}
}
#Override
public Statement apply(Statement statement, Description description) {
return new SimpleRepeatStatement(statement);
}
}
usage:
public class Run10TimesTest {
#Rule
public SimpleRepeatRule repeatRule = new SimpleRepeatRule();
#Test
public void myTest(){...}
}
For a more useful implementation based on an annotation that define which test method has to been executed how often have a look at this blog:
http://www.codeaffine.com/2013/04/10/running-junit-tests-repeatedly-without-loops/

Easy way of running the same junit test over and over?

Like the title says, I'm looking for some simple way to run JUnit 4.x tests several times in a row automatically using Eclipse.
An example would be running the same test 10 times in a row and reporting back the result.
We already have a complex way of doing this but I'm looking for a simple way of doing it so that I can be sorta sure that the flaky test I've been trying to fix stays fixed.
An ideal solution would be an Eclipse plugin/setting/feature that I am unaware of.
The easiest (as in least amount of new code required) way to do this is to run the test as a parametrized test (annotate with an #RunWith(Parameterized.class) and add a method to provide 10 empty parameters). That way the framework will run the test 10 times.
This test would need to be the only test in the class, or better put all test methods should need to be run 10 times in the class.
Here is an example:
#RunWith(Parameterized.class)
public class RunTenTimes {
#Parameterized.Parameters
public static Object[][] data() {
return new Object[10][0];
}
public RunTenTimes() {
}
#Test
public void runsTenTimes() {
System.out.println("run");
}
}
With the above, it is possible to even do it with a parameter-less constructor, but I'm not sure if the framework authors intended that, or if that will break in the future.
If you are implementing your own runner, then you could have the runner run the test 10 times. If you are using a third party runner, then with 4.7, you can use the new #Rule annotation and implement the MethodRule interface so that it takes the statement and executes it 10 times in a for loop. The current disadvantage of this approach is that #Before and #After get run only once. This will likely change in the next version of JUnit (the #Before will run after the #Rule), but regardless you will be acting on the same instance of the object (something that isn't true of the Parameterized runner). This assumes that whatever runner you are running the class with correctly recognizes the #Rule annotations. That is only the case if it is delegating to the JUnit runners.
If you are running with a custom runner that does not recognize the #Rule annotation, then you are really stuck with having to write your own runner that delegates appropriately to that Runner and runs it 10 times.
Note that there are other ways to potentially solve this (such as the Theories runner) but they all require a runner. Unfortunately JUnit does not currently support layers of runners. That is a runner that chains other runners.
With IntelliJ, you can do this from the test configuration. Once you open this window, you can choose to run the test any number of times you want,.
when you run the test, intellij will execute all tests you have selected for the number of times you specified.
Example running 624 tests 10 times:
With JUnit 5 I was able to solve this using the #RepeatedTest annotation:
#RepeatedTest(10)
public void testMyCode() {
//your test code goes here
}
Note that #Test annotation shouldn't be used along with #RepeatedTest.
I've found that Spring's repeat annotation is useful for that kind of thing:
#Repeat(value = 10)
Latest (Spring Framework 4.3.11.RELEASE API) doc:
org.springframework.test.annotation
Unit Testing in Spring
Inspired by the following resources:
blog post
this solution
commented version
Example
Create and use a #Repeat annotation as follows:
public class MyTestClass {
#Rule
public RepeatRule repeatRule = new RepeatRule();
#Test
#Repeat(10)
public void testMyCode() {
//your test code goes here
}
}
Repeat.java
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention( RetentionPolicy.RUNTIME )
#Target({ METHOD, ANNOTATION_TYPE })
public #interface Repeat {
int value() default 1;
}
RepeatRule.java
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class RepeatRule implements TestRule {
private static class RepeatStatement extends Statement {
private final Statement statement;
private final int repeat;
public RepeatStatement(Statement statement, int repeat) {
this.statement = statement;
this.repeat = repeat;
}
#Override
public void evaluate() throws Throwable {
for (int i = 0; i < repeat; i++) {
statement.evaluate();
}
}
}
#Override
public Statement apply(Statement statement, Description description) {
Statement result = statement;
Repeat repeat = description.getAnnotation(Repeat.class);
if (repeat != null) {
int times = repeat.value();
result = new RepeatStatement(statement, times);
}
return result;
}
}
PowerMock
Using this solution with #RunWith(PowerMockRunner.class), requires updating to Powermock 1.6.5 (which includes a patch).
Anything wrong with:
#Test
void itWorks() {
// stuff
}
#Test
void itWorksRepeatably() {
for (int i = 0; i < 10; i++) {
itWorks();
}
}
Unlike the case where you are testing each of an array of values, you don't particularly care which run failed.
No need to do in configuration or annotation what you can do in code.
This works much easier for me.
public class RepeatTests extends TestCase {
public static Test suite() {
TestSuite suite = new TestSuite(RepeatTests.class.getName());
for (int i = 0; i < 10; i++) {
suite.addTestSuite(YourTest.class);
}
return suite;
}
}
There's an Intermittent annotation in the tempus-fugit library which works with JUnit 4.7's #Rule to repeat a test several times or with #RunWith.
For example,
#RunWith(IntermittentTestRunner.class)
public class IntermittentTestRunnerTest {
private static int testCounter = 0;
#Test
#Intermittent(repition = 99)
public void annotatedTest() {
testCounter++;
}
}
After the test is run (with the IntermittentTestRunner in the #RunWith), testCounter would be equal to 99.
This is essentially the answer that Yishai provided above, re-written in Kotlin :
#RunWith(Parameterized::class)
class MyTest {
companion object {
private const val numberOfTests = 200
#JvmStatic
#Parameterized.Parameters
fun data(): Array<Array<Any?>> = Array(numberOfTests) { arrayOfNulls<Any?>(0) }
}
#Test
fun testSomething() { }
}
I build a module that allows do this kind of tests. But it is focused not only in repeat. But in guarantee that some piece of code is Thread safe.
https://github.com/anderson-marques/concurrent-testing
Maven dependency:
<dependency>
<groupId>org.lite</groupId>
<artifactId>concurrent-testing</artifactId>
<version>1.0.0</version>
</dependency>
Example of use:
package org.lite.concurrent.testing;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import ConcurrentTest;
import ConcurrentTestsRule;
/**
* Concurrent tests examples
*/
public class ExampleTest {
/**
* Create a new TestRule that will be applied to all tests
*/
#Rule
public ConcurrentTestsRule ct = ConcurrentTestsRule.silentTests();
/**
* Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
*/
#Test
#ConcurrentTest(requests = 20, threads = 10)
public void testConcurrentExecutionSuccess(){
Assert.assertTrue(true);
}
/**
* Tests using 10 threads and make 20 requests. This means until 10 simultaneous requests.
*/
#Test
#ConcurrentTest(requests = 200, threads = 10, timeoutMillis = 100)
public void testConcurrentExecutionSuccessWaitOnly100Millissecond(){
}
#Test(expected = RuntimeException.class)
#ConcurrentTest(requests = 3)
public void testConcurrentExecutionFail(){
throw new RuntimeException("Fail");
}
}
This is a open source project. Feel free to improve.
You could run your JUnit test from a main method and repeat it so many times you need:
package tests;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.Result;
public class RepeatedTest {
#Test
public void test() {
fail("Not yet implemented");
}
public static void main(String args[]) {
boolean runForever = true;
while (runForever) {
Result result = org.junit.runner.JUnitCore.runClasses(RepeatedTest.class);
if (result.getFailureCount() > 0) {
runForever = false;
//Do something with the result object
}
}
}
}

JUnit test for System.out.println()

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);

Categories