I was wondering if there is a way to dump the state of all local variables when there is an exception, to get a better idea of the state of the environment that caused the exception. Below the variable idsToDump is unknown at run time and I want to find out the state at which value in the collection is causing the NPE.
Example:
public static void main(String[] args) {
HashMap<Integer, String> employees = new HashMap<Integer, String>();
employees.put(1, "James");
Integer[] idsToDump = new Integer[] { 1, 2, 3 };
for (Integer employeeId : idsToDump) {
String name = employees.get(employeeId).toLowerCase();
System.out.println(name + " is employee number: " + employeeId);
}
}
output:
james is employee number: 1
Exception in thread "main" java.lang.NullPointerException
Question:
Is there some JVM argument that I can pass to dump information about the current state of the local variables? ie we get
java.lang.NullPointerException
and (this is the part I'm after)
values: employeeId=2
I want to be able to do this on a client site, so no access to Eclipse or debugging tools, looking for just JVM arguments, can't make code changes either. I have looked through them but couldn't really find anything. In the meantime I'll keep searching there too ;)
I came across a commercial product that does this by simply using a startup -agentlib JVM agent param. I haven't used it yet but intend on giving it a try as it looks very promising.
https://www.takipi.com/product
Anyone have experience with this product?
Given all your restrictions, I can't recommend anything else apart from jdb. Fire that bad boy up and start stepping through the client code line by line. I know you said no debugging tools, but unless they are a JRE only environment you should have jdb installed already.
The easiest thing to do is to run this code in a debugger and step through it. If you can't debug the code then you can use a try/catch block and set employeeId outside of this like:
int debugEmployeeId = -1;
try {
Integer[] idsToDump = new Integer[] { 1, 2, 3 };
for (Integer employeeId : idsToDump) {
debugEmployeeId = employeeId;
...
} catch (Exception e) {
throw new Exception("Missing employeeId = " + Integer.toString(debugEmployeeId));
}
Although you have mentioned that you are not able to do any code changes, here a hint for the case that code changes are still possible: A handy tool to get some more information about the exception is the method "printStackTrace" of the thrown exception object. You may want to use something like this.
try {
...
}
catch ( Exception e ) {
System.out.println( "Exception occured! Reason: " + e.printStackTrace() );
}
Your best option, afaik, is the old manual way: use some sort of logging (be it Log4J, or just stdout), and to explicitly record the variables you're interested in via a catch block.
Like Thomas, I don't know of any current method that can dump variables. However, I believe you want to do so to aid you in your debugging. Here are some simple methods which I use to debug my code using just the console:
1.Learn to read the stacktrace when the exception occurs. It gives you a lot of information on what could be potentially causing the exception. If the particular line that the stacktrace is pointing to doesn't seem to have anything wrong, track back the code and see if it was a prior object that is causing the exception. For example (using some sample code and methods):
Book book = null;
Bookshelf bookshelf = new Bookshelf();
bookshelf.add(book);
bookshelf.getBooks();
Something like that will cause the NPE stacktrace to point to bookshelf, but actually it is book that is causing the NPE.
2.Print out the variables that you suspect are causing the NPE.
for (Integer employeeId : idsToDump) {
System.out.println(employeeId);
String name = employees.get(employeeId).toLowerCase();
System.out.println(name + " is employee number: " + employeeId);
}
Your output will be:
1
2
And then you'll know that 2 is causing the NPE.
3.Comment out the suspicious code and systematically uncomment out the code until the exception occurs, or vice-versa.
Although you may find it tedious and frustrating at times, it really does help in your foundation because with enough practice, you'll soon be able to intuitively spot where the error usually occurs (and hence spend less time on future debugging).
Related
For logging purposes, I created a method logTitle() that prints out the calling method name for our TestNG tests. Sample code is below.
#Test
public void test1() throws Exception {
method1();
}
public static void method1() throws Exception {
Utils.logTitle(2);
}
...
public static void logTitle(Integer level) throws Exception {
// Gets calling method name
String method = Thread.currentThread().getStackTrace()[2].getMethodName();
// This would get current method name
switch (level) {
case 1:
logger.info("=======================================================");
logger.info(method);
logger.info("=======================================================");
break;
case 2:
logger.info("------------------------------------");
logger.info(method);
logger.info("------------------------------------");
break;
case 3:
logger.info("---------------------");
logger.info(method);
logger.info("---------------------");
break;
case 4:
logger.info("--------- " + method + " ------------");
break;
default:
logger.info(method);
}
}
The problem is I am getting different results for logTitle() on two different machines.
Everyone's laptop returns correctly:
2016-06-20 14:22:06 INFO - ------------------------------------
2016-06-20 14:22:06 INFO - method1
2016-06-20 14:22:06 INFO - ------------------------------------
Our dev unix box returns differently:
2016-06-20 14:42:26 INFO - ------------------------------------
2016-06-20 14:42:26 INFO - logTitle
2016-06-20 14:42:26 INFO - ------------------------------------
This works correctly on everyone else's laptop, just not the dev unix box. I think the dev unix box is using IBM's version of Java, while everyone else is using Oracle's version of Java, but not sure if that is the culprit or not.
Any ideas?
From Javadoc:
Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace. In the extreme case, a virtual machine that has no stack trace information concerning this throwable is permitted to return a zero-length array from this method.
So, the only guaranteed way to do this is to use aspects, or collect stack trace with some other custom way. But you can combine this approach with fallback to some way of getting current method's name (for case when your logTitle method will be inlined). It can be found here, for example. Again, no guarantee, but better chance.
The simpler way to have a test method name is by using a #BeforeMethod and injecting the Method. See TestNG's documentation, here.
Just store the name somewhere and use it in your log (why not in a #AfterMethod ?)
My guess, and as mentioned by MeBigFatGuy. This can happen because of the different in implementation/defaults of the JIT compiler of the IBM/Oracle JVM when doing method inlining optimization.
I suggest running the code in the dev unix box with
-Xjit:disableInlining
and see if the issue disappear.
If this will work for you it may be fine for testing, but as mentioned in Alexey Adamovskiy answer we cannot trust java to be consist in the stack frames.
See also:
Would Java inline method(s) during optimization?
Selectively disabling the JIT compiler
Java method inlining
performance considerations
I guess the behavior is JVM specific. In the past I came up with this solution:
// find first stack trace entry that is not in this class
Optional<StackTraceElement> ste = Iterables.tryFind(
Arrays.asList(new RuntimeException().getStackTrace()),
new Predicate<StackTraceElement>() {
#Override
public boolean apply(StackTraceElement input) {
return !input.getClassName().equals(PutYourClassHere.class.getName());
}
});
if (ste.isPresent()) {
LOG.trace("Method called by: {}.{}", ste.get().getClassName(), ste.get().getMethodName());
}
The snippet is using Google Guava because this is for Java 7. If you have Java 8, you can use Streams API and lambdas. I made the ste.isPresent() check because I encountered an empty stack trace once. As far as I remember the Oracle JVM is skipping stack traces when the same exception is thrown over and over again.
EDIT: Java 8 way
Optional<StackTraceElement> ste = Arrays.stream(new RuntimeException().getStackTrace())
.filter(x -> !x.getClassName().equals(Utils.class.getName()))
.findFirst();
I think its the specific depth that is causing the issue which is 2 in your scenario.
So, instead of writing
String method = Thread.currentThread().getStackTrace()[2].getMethodName();
if you write
StackTraceElement[] ste = Thread.currentThread().getStackTrace();
String method = null;
boolean doNext = false;
for (StackTraceElement s : ste) {
if (doNext) {
method = s.getMethodName();
return;
}
doNext = s.getMethodName().equals("getStackTrace");
}
It will work only for JDK 1.5+
The other option is as below:
String method = new Object(){}.getClass().getEnclosingMethod().getName();
Or a slower option will be :
String method = new Exception().getStackTrace()[0].getMethodName();
As this will create an instance of Exception everytime.
Hope that helps you out.
Log4J finds the method name by searching down the stack trace until it finds the target class name which must be passed in, then reads the method name.
In your code, you could use a similar technique - instead of a static method Utils you could create an instance in your test, passing in the class of the test:
Utils utils = new Utils(MyTest.class);
Then use the previously mentioned search technique in the Utils.logTitle() method.
Utils.logTitle() would search forwards through stack trace elements of a newly created Throwable until it finds the first element with the desired target class.
Log4j 2 uses the fully qualified class name of the Logger to locate the class and method from which the Logger was called. The code to find the location follows below. Feel free to use it.
Note that the loop starts from the bottom of the stacktrace; this is necessary to detect exceptional cases where the logger is called recursively (perhaps from the toString() method of an object that was logged). In such cases we want to report the first class/method that called the Logger, not the last one, so we have no choice but to walk the stack trace from the bottom up.
public static StackTraceElement calcLocation(final String fqcnOfLogger) {
if (fqcnOfLogger == null) {
return null;
}
// LOG4J2-1029 new Throwable().getStackTrace is faster
// than Thread.currentThread().getStackTrace().
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
StackTraceElement last = null;
for (int i = stackTrace.length - 1; i > 0; i--) {
final String className = stackTrace[i].getClassName();
if (fqcnOfLogger.equals(className)) {
return last;
}
last = stackTrace[i];
}
return null;
}
I could be wrong about which line is causing the problem, but the error changes everytime I change this if() statement:
try {
while(true) {
String LRU = hashOperation();
System.out.println("In worker thread, this should be valid JSON: " + LRU);
if (jsonValidator.isStringValidJSON(LRU) && !LRU.isEmpty()) {
HashMap<String,String> messageMap = jsonGenerator.readJSON(LRU);
So I assume the problem is with this if() statement. If I write it like this:
if (jsonValidator.isStringValidJSON(LRU)) {
Then the app starts up and I get this exception:
In worker thread, this should be valid JSON:
Exception in worker thread in Main::main: No content to map to Object due to end of input
but if I write it like this:
if (jsonValidator.isStringValidJSON(LRU) && !LRU.isEmpty()) {
Then the app starts up, but then almost instantly dies:
/usr/bin/java -cp /home/jenkins/run-nlp/SSAM.jar com.sofar.SSAM.Main
Starting NLP app 2015/08/30 21:42:28
Loading classifier from dependencies/english.all.7class.distsim.crf.ser.gz ... Killed
The basic idea here is that the app starts up and then spins up some background threads that poll endlessly on Redis, looking for input (the input comes from another app, that publishes data to a channel on Redis).
When I see "Killed" I assume that an Exception went uncaught, but I have this whole Thread::run() wrapped in a try/catch that ends with:
} catch (Exception e) {
System.out.println("Exception in worker thread in Main::main: " + e.getMessage());
}
You can see that this is the Exception message that I get if I do this:
if (jsonValidator.isStringValidJSON(LRU)) {
Although it is possible the error is elsewhere, and I think it is odd that an empty string would be valid JSON, I thought I would screen out that possibility with:
if (jsonValidator.isStringValidJSON(LRU) && !LRU.isEmpty()) {
Why would this one change cause my app to be Killed?
UPDATE:
I refactored the app to this:
static void processMessage(ssamBrain ssamBrain, Jedis jedis, HashMap<String, String> responseMap, JsonGenerator jsonGenerator, JSONValidator jsonValidator, String LRU) {
try {
if (!LRU.isEmpty()) {
HashMap<String,String> messageMap = jsonGenerator.readJSON(LRU);
Transformer transformer = new Transformer();
Again, the line that causes the problem seems to be:
if (!LRU.isEmpty()) {
If I don't have that if() statement, then the code gets:
java.io.EOFException: No content to map to Object due to end of input
on the next line, since an empty string is not valid JSON.
But when I add this:
if (!LRU.isEmpty()) {
Then my app dies on startup.
Maybe autoboxing is the problem? Or the absence of it? Assume for now:
LRU = "";
I assume I can call methods on it, but maybe not? And why wouldn't I get an Exception?
It's possible the problem is elsewhere, but that if() statement seems to be the main thing that causes the problem to surface.
UPDATE
UPDATE
The app sometimes survives for a few minutes, but other times it dies after a few seconds. So I guess I need to ask:
1.) when a Java app says "Killed" in the terminal, does that always mean that an Exception went uncaught?
2.) what might cause such variable behavior?
How to works if operator:
if (CONDITION_1 && CONDITION_2){
doSomething();
}
checks CONDITION_1 - if it is true:
checks CONDITION_2 - if it is true:
runs doSometring().
If CONDITION_1 is false or throws an exception, CONDITION_2 never checks.
Please, show the exception stackTrace.
Change:
if (jsonValidator.isStringValidJSON(LRU) && !LRU.isEmpty())
to:
if (!LRU.isEmpty() && jsonValidator.isStringValidJSON(LRU))
So, you first check if LRU is empty and if it is not - you run validation.
I have a cucumber scenario and the step uses assertEquals. My results report shows the stack trace which is not end user friendly. How can I suppress it
Scenario: Add two numbers
Given I have two inputs "3" and "2"
When I add them
Then the output should be "15"
You're correct in observing that the default XML output (assuming you're not outputting to JSON or text, but you didn't say) from a Junit tests show stack traces for failed steps. This isn't actually a Cucumber thing. CucumberOptions won't help you here.
You can:
Use a different or custom Runner for your test and then setup a tag that controls what is included in the output, or what will be read by the CI software of your choosing. For example the Confulence API API for doing this tells how "debugger"
Same type of deal for Ant Scripts to tweak the output, so that is doesn't show the output. A good Tutorial for learning how to use Any scripts to fire off your Cucumber JUnit Test is here.
Other have build a custom formatter for JUnit by implementing XMLJUnitResultFormatter API, explained more here - How do I configure JUnit Ant task to only produce output on failures?
Hope that gives you what you need.
I was also facing same issue with my Cucumber-Selenium-Java project. In the cucumber reports, it was generating around 40 lines of stacktrace. Due to this, it was impacting look and feel of the report. And the end user/client was little concerned about it. Because he/she was not really able to figure out the actual use of this stacktrace. So, I came up with below idea/approach. It's little bit tricky but, it's worthy.
Few notes before starting:
We cannot completely disable stacktrace in in all the cases. But we can modify the stacktrace and then, re-throw the new exception with useful and shortened stacktrace.
You need to be aware about frequently faced exceptions, errors. So that, we can create custom exception depending on the exceptions.
In the stacktrace it will generate few line of code from wrapper APIs, few lines from Junit/TestNg, few lines for java and selenium and there will be only one or two lines in the stacktrace, where actually our issue occurred.
Our test classes must be in unique package. So that, we can filter the stacktrace trace with package name and get the class name, line number and method name of actual issue and we can use this information in throwing custom exception. Hence, it will be easy to figure out the actual line of issue occurred. In my case all the classes were in package named "page". If you have more than one packages for your classes, then you can accordingly add string conditions in below code.
We need to wrap the test code in try-catch block. And while catching, we need to use Throwable class not exception class. Because, if there is any assertion failure, then Exception class won't be able to handle the issue as you know all the assertions come under Error class and Throwable is the parent of Error and Exception.
If we throw the new exception in catch block, then, it will change the line number in stacktrace, where actual issue occurred. So it will be difficult to figure out the actual line of issue. In order to avoid it, we need to get the class name, line number, method name of actual issue and store it in StackTraceElement class and use it in throwing new exception.
Some exceptions like "NoSuchElementException" provides lot of information in their cause and most of it is not really required, So we need to modify the content of it's message by using substring(), indexOf() and replaceAll() methods of String class in Java. And then, provide the modified information in new exception.
Few important Java method from Throwable java class and their description: (i) getStackTrace(): This method will return us array of StackTraceElement class. StackTraceElement class will provide us the class name, method name, line number at which issue is occurred. (ii) setStackTrace(): This method is used to provide a custom stacktrace to new Exception. (iii) getCause(): This method will provide the issue message from cause of exception. But sometimes, it might return null. Because for some exceptions "cause" might not be specified. So this needs be surround in try catch block and here we need to use getMessage() method for getting the actual error message. (iv) getClass(): This method will return the actual exception class name. We will use this method for figuring out the exception class name and then, we will use it for providing specific implementation for different different exception classes. Note: "getClass()" method is not from "Throwable" class. It is from Object class.
You need to create a common method for handling all the exceptions and reuse this method in all the required classes. e.g.: I have named the method as "processException" and placed it in "ReusableMethod" class.
Note that, I am using package name "page" in below method (line#8), because all my test classes are placed in this package. In your case you need to update the package name as per your need. Also, I have written custom cases for two exceptions only: NoSuchElementException & AssertionError. You might need to write more cases as per your need.
public void processException(Throwable e) throws Exception {
StackTraceElement[] arr = e.getStackTrace();
String className = "";
String methodName = "";
int lineNumber = 0;
for (int i = 0; i < arr.length; i++) {
String localClassName = arr[i].getClassName();
if (localClassName.startsWith("page")) {
className = localClassName;
methodName = arr[i].getMethodName();
lineNumber = arr[i].getLineNumber();
break;
}
}
String cause = "";
try {
cause = e.getCause().toString();
} catch (NullPointerException e1) {
cause = e.getMessage();
}
StackTraceElement st = new StackTraceElement(className, methodName, "Line", lineNumber);
StackTraceElement[] sArr = { st };
if (e.getClass().getName().contains("NoSuchElementException")) {
String processedCause = cause.substring(cause.indexOf("Unable to locate"), cause.indexOf("(Session info: "))
.replaceAll("\\n", "");
Exception ex = new Exception("org.openqa.selenium.NoSuchElementException: " + processedCause);
ex.setStackTrace(sArr);
throw ex;
} else if (e.getClass().getName().contains("AssertionError")) {
AssertionError ae = new AssertionError(cause);
ae.setStackTrace(sArr);
throw ae;
} else {
Exception ex = new Exception(e.getClass() + ": " + cause);
ex.setStackTrace(sArr);
throw ex;
}
}
Below is the sample Method to showcase the usages of above method in Test Class methods. We are calling the above created method by using the class reference, which is "reuseMethod" in my case. And we are passing the caught Throwable reference "e" to the above method in catch block:
public void user_Navigates_To_Home_Page() throws Exception {
try {
//Certain lines of code as per your tests
//element.click();
} catch (Throwable e) {
reuseMethod.processException(e);
}
}
Here are few screenshots for implementation of NoSuchElementException:
Before Implementing this approach:
After Implementing this approach:
How can I get the results of my JUnit assertions to be printed [to standard output]?
I have some tests like this:
#Test
public void test01()
{
Position p = getPositionAt('a', 1);
assertNotNull("a1 exists", p);
assertNotNull("figure exists a1", p.getFigure());
p = getPositionAt('a', 2);
assertNotNull("exists a2", p);
assertNull("figure exists a2", p.getFigure());
p = getPositionAt('b', 1);
assertNotNull("exists b1", p);
assertNull("figure exists b1", p.getFigure());
}
This is the printed output format I am hoping to get:
a1 exists -success
figure exists a1 -success
exists a2 -success
figure exists a2 -succcess
exists b1 -succcess
figure exists b1 -failed
Is there way to do this using runners and suites? Or does there exist any assertSuccess(), assertFailed() methods?
First, you have two issues not one. When an assertion fails, an AssertionError exception is thrown. This prevents any assertion past this point from being checked. To address this you need to use an ErrorCollector.
Second, I do not believe there is any way built in to JUnit to do this. However, you could implement your own methods that wrap the assertions:
public static void assertNotNull(String description, Object object){
try{
Assert.assertNotNull(description, object);
System.out.println(description + " - passed");
}catch(AssertionError e){
System.out.println(description + " - failed");
throw e;
}
}
All the assertXXX methods have a form that allows for displaying a String on error:
assertNotNull("exists a2", p); // prints "exists a2" if p is null
There is no particular value in printing a message on success.
EDIT
Junit typically provides 2 forms of an assert. To follow the example above, you can test for a null value in 1 of 2 ways:
assertNotNull(p)
or
assertNotNull("my message on failure", p)
The framework will print the error messages with no other effort required by you (it's provided by the framework).
To test for exceptions you would use the following pattern:
try{
someCall();
catch(Exception e){
fail(): // exception shouldn't happen, use assertTrue(true) if it should
}
Again, there are versions of these methods for adding a message
Check the API
One last resort option is to pair each assert with a corresponding System.out.println, though obviously that is less than ideal. Still, it will solve the problem if all else fails.
Existing Answers/Comments here contain enough info to understand how to print something based on JUnit assertions - but they also explain how doing so is probably not what you actually want to do, and is probably missing the point of running unit tests in the first place.
You should be viewing the results of the tests themselves, instead of trying to print something while you don't understand how/where to view test results themselves.
Now then how/where to view results themselves depends on how you are running your tests - you need to understand how you are running your tests, and then research how to view test results according to how you are running them. Here are a few (but not limited to) examples:
Running tests in IntelliJ
Running tests in Eclipse
Running tests on command line
Running tests in Jenkins
Here is some sample code to illustrate our issue:
A a = null;
try {
a = new A();
a = doSomethingThatWillThrowAnException();
} finally {
System.out.println("A = " + a);
}
The question is what is the value of 'a' as printed in the finally block...
I am not sure and I think I stumbled across something that might not be completely described. I observed on my laptop (jdk1.6.0.16 on x86) that 'a' is equal to A(). However, with a JDK 1.4 on Solaris I think that that the value is null (like if the assignment was performed even though the exception is thrown). This is obviously linked to a bug and we will deploy a version without the assignment just to make sure but we would like to know if one of you also noticed this or have some kind of explanation to propose.
What we will do, also, is to make a sample program to demonstrate this on the problematic JDK... and we will post the results.
The assignment should definitely not happen when an exception occurs - this would be a very serious bug in the JVM. But I'd first suspect that the exception actually occurs somewhere else (such in the constructor A()).
I would assume a == new A() unless it is optimized away. Isn't the code a bit silly looks like:
a=1;
a=2;
Maybe rewrite to the intend of your code:
A a = null;
try {
a = doSomethingThatWillThrowAnException();
} catch( ... ) {
a = new A();
}
Just did the test on Solaris with Sun JDK_1.4.2_05 on Solaris with the following program
public class Test {
public static void main(String[] args) throws Exception {
String test = null;
try {
test = "step1";
test = getString();
} finally {
System.out.println(test);
}
}
public static String getString() {
throw new RuntimeException();
}
}
I get the "step 1" in the console alright.
As other user have suggested, I think that the most likely is that the exception is thrown in the A() constructor. ( I hope that's the case, otherwise that would require some quite nasty defensive code )
If the optimizer can make sure that new A() has no side effects, it will optimize the first assignment away. To isolate this case, disable the JIT and run the code again. If a != null afterwards, you're seeing an optimizer glitch.
The obvious fix is to more the new A() before the try block:
A a = new A();
try {
a = doSomethingThatWillThrowAnException();
} finally {
System.out.println("A = " + a);
}
You could try compiling the code then looking at the bytecode to see what is going on. I use
the bytecode outliner eclipse plugin from http://andrei.gmxhome.de/eclipse/
I ran the code on Solaris 10 with the JDK 1.4.2 too and it had the correct behaviour. The problem was that the code in production was not the one I was looking at... (previous version)
It was interesting reading your answers though since it made it clear that optimizer glitches can happen and it is always a good idea to second guess what is going on under the hood.
Mental note for next time: "First, check the obvious: If you are having a strange behaviour, the code you are seing might not be what has been executed."
Thanks again,
Cedric