How to read console output in maven surefire unit test - java

I am trying to test a method which has to print a specific string to System.out.
I have used this answer to get this working with JUnit.
This works fine with JUnit, but the tests are then run in a CI environment, by Maven surefire. The test then fails, supposedly because Maven catches System.out and it is not available to the test ?
Can someone please help me to find a way to use the console output in this Surefire test ?
Here is my test :
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);
}
#Test
public void testUpdateData() throws Exception {
MyData data = new MyData();
DataUtil.updateData(data);
Assert.assertTrue(outContent.toString().contains("is updating data within last 24h")); // assert that warning issued
}
The tested class :
public final class DataUtil {
public static void updateData(Data d) {
/// do stuff
if (/*condition*/) {
System.out.println("data " + d.id + "is updating data within last 24h");
}
}
}
Output with Maven testing :
testUpdateData Time elapsed: 0.035 sec <<< FAILURE!
java.lang.AssertionError: null
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)

I fixed this with changing the System.out.println() to logging with log4j.
Following Raedwalds comment and link7 I decided to discard the old system output. But instead of using PrintStreams I went one step further and refactored the code to use Log4j logging.
Then I used this answer to read the outputted logs from within the unit test.

Related

Nifi ExecuteGroovyScript trigger onStart with TestRunner

I am currently struggling with writing tests for my ExecuteGroovyScript process. I am able to do a lot of things with the Nifi Testrunner and MockingFlowFiles but I dont find a way to trigger the onStart callback for the GroovyScript.
I need the onStart as described here to initially (and only once) load a config for the processor and provide it to the script. It works as described in Nifi itself, but the onStart is not called while executing the tests with the TestRunner.
#BeforeEach
public void setup() throws IOException {
runner = TestRunners.newTestRunner(ExecuteScript.class);
runner.setProperty("Script Engine", "Groovy");
runner.setProperty("converterconfig", IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("config.json")), StandardCharsets.UTF_8));
runner.setProperty(ScriptingComponentUtils.SCRIPT_BODY,
IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("converter.groovy")), StandardCharsets.UTF_8));
runner.assertValid();
}
#Test
public void processSuccessfulEvent() throws IOException {
String inputString = IOUtils.toString(Objects.requireNonNull(this.getClass().getResourceAsStream("input.json")), StandardCharsets.UTF_8);
runner.enqueue(inputString);
runner.run();
runner.assertTransferCount(ExecuteScript.REL_SUCCESS, 1);
}
//Groovyscript
static onStart(ProcessContext context){
//do stuff with the config, but this is never called/triggered in the testrunner
def config = context.getProperty("converterconfig")
...
}
Does anyone have an advise how to get the tests to trigger the onStart? Nifi version is 1.12 and Groovy 2.4.16
Thank you in advance.

How to unit test writing a file to AWS Lambda output stream?

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.

Why does assertion fail under RUN but not under DEBUG?

Very strange behavior in a unit test. The code is on another computer so I'll shorthand the main aspect of it.
The problem is
When I test as RUN the test checks two objects for 10 properties, it fails saying that the object contains 19 properties.
When I test as DEBUG the test passes for both of the objects where they each have 10 properties.
How the heck is this happening?
#Test
public void testConverterTwoObjects(){
InputStream inFile = this.getClass().getResourceAsStream(TEST_TWO_OBJECTS);
try{
List<MyObject> objs = getConvertedObjects(inFile);
MyObject mob1 = objs.get(0);
MyObject mob2 = objs.get(1);
assertionCheck(mob1);
assertionCheckTwo(mob2);
} catch(Exception e){
// logging
} finally {
try{
inFile.close();
} catch(IOException ioe){
// logging
}
}
}
private void assertionCheck(MyObject t){
assertNotNull(t);
assertEquals(10, t.getPropertyCount());
assertEquals("ALPHA", t.getType());
...
}
private void assertionCheckTwo(MyObject t){
assertNotNull(t);
assertEquals(10, t.getPropertyCount());
assertEquals("BRAVO", t.getType());
...
}
I had a similar problem in PyCharm (Intellij IDEA for Python). After searching hours, it turned out that the garbage collector's behaviour is different in debug mode than in run mode.

Testing System.out.println not working but System,out.print using JUnit

I am learning unit testing with JUnit in Netbeans. But I know how the JUnit works and how to test the System.out.print -
JUnit test for System.out.println(). I am a very new to JUnit because I just started JUnit today.
This is my test class
public class CDTest {
CD cd;
private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
private final ByteArrayOutputStream errContent = new ByteArrayOutputStream();
public CDTest() {
}
#BeforeClass
public static void setUpClass() {
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void setUp() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
#After
public void tearDown() {
System.setOut(null);
System.setErr(null);
}
#Test
public void testSystemOutPrint(){
System.out.print("hello");
System.out.print("hello again");//Please pay attention here. Just System.out.print()
assertEquals("hellohello again", outContent.toString());
}
}
When I run the test, it is working successfully. Now I am only testing to the System.out.print. But when I test System.out.println() as below
#Test
public void testSystemOutPrint(){
System.out.print("hello");
System.out.println("hello again"); //Please pay attention here for println()
assertEquals("hellohello again", outContent.toString());
}
The above code give me this error.
I tried adding system to fix the error like this.
#Test
public void testSystemOutPrint(){
System.out.print("hello");
System.out.println("hello again"); //Please pay attention here for println()
assertEquals("hellohello again ", outContent.toString());//Please pay attention to the space after "again"
}
As you can see above, I added a space after "again". It is still giving me the error when I run. I tried this too
assertEquals("hellohello again\n", outContent.toString());
How can I test System.out.println instead of System.out.print?
Try this
String expected = "hellohello again " + System.getProperty("line.separator");
assertEquals(expected, outContent.toString());
I haven't run this, but I suspect System.out.println is adding a linebreak to the end of "hellohello again". So your strict equals is probably failing for that.
You may want to consider either changing your assertion to
assertTrue(outContent.toString().startsWith("hellohello again"));
Or add a line break to the end of your expected String. That might be tricky because it will change depending on the system running your tests. So you might need something like System.getProperty("line.separator"); or a similar solution to getting the correct line break character at runtime.
System.out.println prints a new line. Change: "hellohello again" to
"hellohello again" + System.lineSeparator()

Get result (errorCount, failureCount...) of JUnitTest

I figured out how to use the Ant API to run a JUnit Test and create an XML of the result.
String pathToReports = "/tmp/junitreports";
Project project = new Project();
JUnitTest test = null;
try
{
new File(pathToReports).mkdir();
JUnitTask task = new JUnitTask();
project.setProperty("java.io.tmpdir",pathToReports);
task.setProject(project);
FormatterElement.TypeAttribute type = new FormatterElement.TypeAttribute();
type.setValue("xml");
FormatterElement formater = new FormatterElement();
formater.setType(type);
task.addFormatter(formater);
test = new JUnitTest(TestClass.class.getName());
test.setTodir(new File(pathToReports));
task.addTest(test);
task.execute();
}
...
TestClass:
public class TestClass
{
#Test
public void test()
{
fail("failed");
}
}
The Code works just fine. The XML is created and I can see that the test "failed".
Now my question: is there any way to also get the test results programatically? I expected to get an updated version of the JUnitTest object somehow where I can call the method "failureCount()".
test.failurecount() after execution of the task returns 0 of course. Parsing the XML seems odd to me as the number of failures should already be stored somewhere.
You could have a variable (int failedTests) increment each time a test fails. You could do this by using a TestWatcher rule.
After all the tests have run you could print it out (or do whatever you wanna do with it...) with:
#AfterClass
public static void printFailedTestsCount() {
System.out.println(failedTests + " tests failed.");
}

Categories

Resources