Testing println output with JUnit - java

I am testing a simple helloWorld class.
package Codewars;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
And I have a test class as follows (based on the answer ):
import static org.junit.jupiter.api.Assertions.*;
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 helloWorldTest {
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final PrintStream originalOut = System.out;
#BeforeEach
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
}
#AfterEach
public void restoreStreams() {
System.setOut(originalOut);
}
#Test
void test() {
HelloWorld.main(null);
assertEquals("Hello World\n", outContent.toString());
}
}
It results in failure with error message as follows:
org.opentest4j.AssertionFailedError: expected: <Hello World
> but was: <Hello World
>
at org.junit.jupiter.api#5.5.1/org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
at org.junit.jupiter.api#5.5.1/org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
...
It seems like the strings are same and still the error is thrown?
Thank you in advance.

Make sure that your line separator is equal to \n on your system.
This is not the case on Windows.
To fix the test, modify it to take system-specific separator into account
assertEquals("Hello World" + System.lineSeparator(), outContent.toString());

Related

Junit 5: Expected exception to be thrown, but nothing was thrown

I have very strange behavior for the following test:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.NoSuchElementException;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class TestLogger {
static IPcdsLogger logger;
static Logger LOGGER = LoggerFactory.getLogger(TestLogger.class);
#BeforeEach
public void setup() {
logger = PcdsLoggerFactory.getLogger(TestLogger.class);
}
#AfterEach
public void tearDown() throws IOException {
PrintWriter writer = new PrintWriter(new File("src/test/resources/temp/test.log"));
writer.print("");
writer.close();
}
#AfterAll
public static void deleteFile() throws IOException {
logger.close();
FileUtils.deleteDirectory(new File("src/test/resources/temp"));
}
#Test
public void testJsonParams() throws IOException {
logger.builder()
.add("hello", "world")
.add("bob", "alice")
.debug("wtf");
assertEquals("world", readLine(0).get("hello"));
assertEquals("alice", readLine(0).get("bob"));
}
#Test
public void testLogLevelTraceCheck() {
logger.traceLevel()
.ifPresent(b -> b.add("hello", "world").trace());
assertThrows(NoSuchElementException.class, () -> readLine(0));
}
private JSONObject readLine(int lineNo) throws IOException {
try (Stream<String> lines = Files.lines(Paths.get("src/test/resources/temp/test.log"))) {
String line = lines.skip(lineNo).findFirst().get();
return new JSONObject(line);
}
}
When I run the test individually, it passes.
When I run all the tests, on the second run I get the following error for the testLogLevelTraceCheck:
Expected java.util.NoSuchElementException to be thrown, but nothing was thrown.
org.opentest4j.AssertionFailedError: Expected java.util.NoSuchElementException to be thrown, but nothing was thrown.
at app//org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:71)
at app//org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:37)
at app//org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:3082)
I thought it was enough to reinstantiate the logger in #BeforeEach, but somehow it doesn't happen all the time this.
Do you have any suggestions?
If it does not throw, it could mean that the file is actually there and has some content. This makes sense, since just calling PcdsLoggerFactory.getLogger(TestLogger.class) does not seem to guarantee to delete the logfile then.

Mokito/Java - Static Methods Mock

For example I have the following classes below:
public class TesteEstatico {
public static String teste(){
return "FOO";
}
}
And I have a class that uses her method:
public class UsaTesteEstatico {
public String metodoParaTeste1 (){
return TesteEstatico.teste() + " BAR ";
}
public String metodoParaTeste2 (){
return "FOO "+TesteEstatico.teste() + " BAR ";
}
}
Test class:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class) public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#Test
void teste1(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
Error I get when trying to run the tests:
org.mockito.exceptions.base.MockitoException:
For TesteEstatico, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
Versions of the libs that are in the project:
junit-jupiter 5.5.2
mockito-junit-jupiter 3.2.14
mockito-inline 3.2.14
Any idea how to solve this, i've tried a few things but nothing successful.
NOTE: I cannot change or add any new libraries as it is a restricted project.
You should use try-with-resources block in each of the tests to close the mockStatic.
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
#Test
void teste1(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
}
#Test
void teste2(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
}
Note on mockStatic in #BeforeAll
Using #BeforeAll is a trap and bad advice.
You should strive for independent tests that don't affect each other.
This is not the case for mockStatic called in #BeforeAll, as stubbing from test methods outlive the test methods.
For example
// BAD CODE DONT USE
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
static MockedStatic<TesteEstatico> ms;
#BeforeAll
public static void init() {
ms = Mockito.mockStatic(TesteEstatico.class);
}
#AfterAll
public static void close() {
ms.close();
}
#Test
void teste1() {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2() {
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
teste2 prints:
FOO BANANA BAR if run after teste1
FOO null BAR if run separately
This is precisely what you want to avoid.
you need to use static block to mock it.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#BeforeAll
public static void init(){
Mockito.mockStatic(TesteEstatico.class);
}
#Test
void teste1(){
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}

iterative testing using junit

I have a bunch of test inputs that I would like to run and compare the output with expected:
#Test
void test () throws IOExeption {
for (File i : readDir()) {
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
}
I would like to run the tests using JUnit. But if I do it like the above then JUnit will stop after encountering the first test failure. Is there a better way to do this other than making each file its own test case like below?
#Test
void test1 () throws IOExeption {
File i = readFile("1.txt");
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
#Test
void test2 () throws IOExeption {
File i = readFile("2.txt");
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
I think, that you could use Parameterized. This is standard feature of JUnit. Below you can see an example.
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
#RunWith(Parameterized.class)
public class Foo {
#Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] { { "1.txt" }, { "2.txt" } });
}
#Parameterized.Parameter // first data value (0) is default
public /* NOT private */ String fileName;
#Test
public void test() {
File i = readFile(fileName);
File out = foo(i);
assertEquals(FileUtils.readLines(expected), FileUtils.readLines(out));
}
}
I have not found JUnit official documentation about this, but you can find more details e.g. in this tutorial: https://www.tutorialspoint.com/junit/junit_parameterized_test.htm

Extent report shows only last test case result

Extent report version - 3.0
Language - Java and TestNG classes
I have a class - ExtentManager.java
package framewrk;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
public class ExtentManager {
private static ExtentReports extent;
private static ExtentTest test;
private static ExtentHtmlReporter htmlReporter;
private static String filePath = "./extentreport.html";
public static ExtentReports GetExtent(){
extent = new ExtentReports();
htmlReporter = new ExtentHtmlReporter(filePath);
// make the charts visible on report open
htmlReporter.config().setChartVisibilityOnOpen(true);
// report title
String documentTitle = prop.getProperty("documentTitle", "aventstack - Extent");
htmlReporter.config().setDocumentTitle(documentTitle);
}
public static ExtentTest createTest(String name, String description){
test = extent.createTest(name, description);
return test;
}
public static ExtentTest createTest(String name){
test = extent.createTest(name, "");
return test;
}
}
and 2 testNG classes as follows
TC1.java
package framewrk;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
public class TC1 {
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how fail works");
test.log(Status.INFO, "fail check started");
test.fail("Test fail");
}
#AfterClass
public void tear()
{
extent.flush();
}
}
TC2.java
package framewrk;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.Status;
public class TC2 {
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how pass works");
test.log(Status.INFO, "pass check started");
test.pass("Passed");
}
#AfterClass
public void tear()
{
extent.flush();
}
}
If run these 2 test cases, I am getting only last testcase result, for the 1st testcase result, it's not displayed on the extent report.
Note that there is not append parameter for extent report 3.0.
How to get all test case results on extent report?
In the above approach, you are creating a new extent report in each Class. That is why you are getting only the latest executed test result.
You can create a common superclass for both TC1 and TC2 classes. In the superclass you can create #AfterClass and #BeforeClass functions. Then it should work.
Hope it helps!
I got one approach that works well, 1st check if the extent object is already created? if yes then return the object without reinitialising the extent object, here is how it looks
Under the ExtentManager class [as shown in the question], add this code block
public static ExtentReports getInstance() {
if(extent == null) {
GetExtent();
}
return extent;
}
Now under your testNG tests, before class annotation, call the above method
#BeforeClass
public void setup(){
extent = ExtentManager.getInstance();
}
In your case ExtentManager.GetExtent() this method overrides the previously created report hence only the last test result shows up in report. Make sure this method is only called during the whole set of your test start, best way is to do it by implementing ITestListener
Use this method extent.flush() in #aftersuite. because this statement generates the result
{
public class TC1
{
static ExtentReports extent;
static ExtentTest test;
#BeforeClass
public void setup(){
extent = ExtentManager.GetExtent();
}
#Test
public void OpenUT(){
test = extent.createTest("Testing how fail works");
test.log(Status.INFO, "fail check started");
test.fail("Test fail");
}
#Test
public void OpenUT1(){
test = extent.createTest("Testing how pass works");
test.log(Status.INFO, "pass check started");
test.pass("Passed");
}
#aftersuite
public void tear()
{
extent.flush();
}
}

How to configure JUnit rules to apply to specific test

Is it possible to have a Junit rule only apply to specific tests? If so, how do I do that?
The code below exemplifies what I want to do: each time I have #Rule, I want the method below that to have the specific rule that has been annotated to run with it. I only want that rule to run with the corresponding test. I don't want anything other tests to be affected by the rule.
In this case, when I run these tests, I see that one of the tests the EmptyFileCheck, gives a File DNE does not exist, but I have used a separate annotation for that function, so I had thought that it would run with a different context, supplying the Empty, but instead DNE is till being used.
import static java.lang.System.in;
import static java.lang.System.setIn;
import static org.junit.Assert.fail;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.nio.channels.Pipe;
import static org.hamcrest.core.AllOf.allOf;
import org.hamcrest.Matcher;
import org.hamcrest.core.AllOf;
import static org.hamcrest.Matchers.*;
import org.hamcrest.text.StringContains;
import org.hamcrest.text.StringEndsWith;
import org.hamcrest.text.StringStartsWith;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.TextFromStandardInputStream;
import org.junit.runner.RunWith;
public class UnitTests {
private Mockery context = new Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
private main mn;
private InputStream oldIn;
private PrintStream oldOut;
private InputStream mockIn;
private InputStreamReader mockinputStream;
private PrintStream mockOut;
private BufferedReader reader;
private Expectations exp;
#Before
public void setMinimalMockingExpectations() throws IOException {
exp = new Expectations() {{ }};
mn = context.mock(main.class);
mockinputStream = context.mock(InputStreamReader.class);
oldIn = System.in;
oldOut = System.out;
mockIn = context.mock(InputStream.class);
mockOut = context.mock(PrintStream.class);
System.setOut(mockOut);
}
public void configureExpectations(boolean fileOrInput, boolean verbosity) {
exp.one(mockOut).println("Do you want to process standard (I)nput, or a (F)ile? I/F");
if (fileOrInput) { //it's a file
exp.one(mockOut).println("Enter filename: ");
} else { //it's not
}
}
#After
public void reset() {
System.setOut(oldOut);
}
#Rule
public final TextFromStandardInputStream FileNotFoundException
= new TextFromStandardInputStream("F\nDNE\n");
#Test(expected=FileNotFoundException.class)
public void EnsureFileCheckExists() throws IOException {
final String fileName = "DNE";
configureExpectations(true, false);
exp.one(mn).checkFile(fileName);
context.checking(exp);
mn.main(null);
}
#Rule
public final TextFromStandardInputStream FileReadAccessDenied
= new TextFromStandardInputStream("F\nUnderPriviledged\n");:w
#Test(expected=FileNotFoundException.class)
public void FileReadAccessDenied() throws java.io.FileNotFoundException {
final String fileName = "UnderPriviledged";
configureExpectations(true, false);
//exp.oneOf(mn).checkFile(with()); TODO: fix ME!
context.checking(exp);
mn.main(null);
}
#Rule
public final TextFromStandardInputStream EmptyFileCheck
= new TextFromStandardInputStream("F\nEmpty\n");
#Test
public void EmptyFileCheck() throws java.io.FileNotFoundException {
final String fileName = "Empty";
configureExpectations(true, false);
exp.one(mn).checkFile(fileName);
context.checking(exp);
mn.main(null);
}
}
You could have a setter in your Rule which is the first thing that gets called in the rule. Something like this, from ExpectedException:
// These tests all pass.
public static class HasExpectedException {
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void throwsNothing() {
// no exception expected, none thrown: passes.
}
#Test
public void throwsNullPointerException() {
thrown.expect(NullPointerException.class);
throw new NullPointerException();
}
#Test
public void throwsNullPointerExceptionWithMessage() {
thrown.expect(NullPointerException.class);
thrown.expectMessage("happened?");
thrown.expectMessage(startsWith("What"));
throw new NullPointerException("What happened?");
}
}
Any reason not to just take the code out of the #rule annotation and move it to the start of the test body?

Categories