Eclipse JUnit assertEquals(String, String) - disable square bracket diff in Failure Trace - java

JUnit assertEquals Changes String
In short: assertEquals("Hello World", "HelloWorld"); appears in the Failure Trace as expected:<Hello[ ]World> but was:<Hello[]World>
Great. Definitely didn't waste my time trying to figure out why the heck my parser was randomly throwing square brackets around.
How do I disable this?
I am using Eclipse 4.19.0 for Java, JUnit 4.10.

You cannot.
These brackets are added by junit.framework.ComparisonCompactor that is being used in org.junit.ComparisonFailure assertion error's getMessage method (this error is being thrown by assertEquals btw)
// ComparisonFailure class
public String getMessage() {
return new ComparisonCompactor(MAX_CONTEXT_LENGTH, fExpected, fActual).compact(super.getMessage());
}
in ComparisonCompactor these brackets are hardcoded and it seems that there is no configuration that can be provided, also ComparisonCompactor cannot be injected (the same for ComparisonFailure - you are not able to provide custom implementation for them)
public class ComparisonCompactor {
private static final String ELLIPSIS= "...";
private static final String DELTA_END= "]";
private static final String DELTA_START= "[";
// ...
private String compactString(String source) {
String result= DELTA_START + source.substring(fPrefix, source.length() - fSuffix + 1) + DELTA_END;
As far as I see even in Junit 4.13 it looks exactly the same so even bumping up dependency will not help here (however you could give a try to Junit5 that with usage of Assertions.assertEquals will produce expected: <Hello world> but was: <Helloworld> output - but obviously it won't be just bumping up dependency version)
By the way Eclipse has nothing to do with it, the same output you will get in other IDEs (or in console)
What I would suggest (however it's not an answer for your question) is to use assertion library like AssertJ that can give you more control but also make you assertions more fluent.
An example in AssertJ would look like
assertThat("Hello World").isEqualTo("HelloWorld");
and is producing
Expecting:
<"Hello World">
to be equal to:
<"HelloWorld">
but was not.

Related

How to define ParameterType with code-dependent RegEx in Cucumber without TypeRegistry?

In Cucumber 7.4.1+ TypeRegistry is deprecated in favour of annotations.
Indeed, as of today, I have never used anything but #ParameterType to define my ParameterTypes. Searching for alternatives, TypeRegistry is the only one I have found - but if it is "on the way out", of course I'd rather not start using it now.
Given a construct like this I cannot use annotations because those cannot take static parameters:
enum SpecialDate implements Supplier<Date> {
TODAY { #Override public Date get() { return Date(); } },
// YESTERDAY, etc.
;
static String typeSafeRegEx() {
return Arrays.stream(Zeitpunkt.values())
.map(SpecialDate::specName)
.collect(Collectors.joining("|"));
}
static SpecialDate from(final String specName) {
return valueOf(StringUtils.upperCase(specName));
}
String specName() {
return StringUtils.capitalize(StringUtils.lowerCase(this.name()));
}
}
public class ParameterTypes {
// does not compile: "Attribute value must be constant"
#ParameterType("(" + SpecialDate.typeSafeRegEx() + ")")
public Date specialDate(final String specName) {
return SpecialDate.from(specName).get();
}
}
A so-specified regEx is nice, because it will only match values guaranteed to be mappable, so I need no additional error handling code beyond Cucumber's own. The list of allowed values is also maintenance-free (compared to a "classic" switch which would silently grow incorrect when adding new values).
The alternative would be to use an unsafe switch + default: throw, strictly worse because it has to be maintained manually.
(Or, I guess, to just valueOf whatever + wrap into a more specific exception, when it eventually fails.)
To me, Cucumber's native UndefinedStepException appears to be the best outcome on a mismatch, because everyone familiar with Cucumber will immediately recognise it, unlike a project-specific one.
I see that e.g. the ParameterType class is not deprecated but cannot seem to find information how to use it without TypeRegistry.
FWIW:
Updating the libraries or Java would not be an issue. (But downgrading is sadly not viable.)
Business Specialists want to write examples like [Today], [Today + 1], [Yesterday - 3], etc. If this can be realised more elegantly using a different approach, X/Y answers would also be welcome.
An example step looks like this:
And I enter into the field 'Start of Implementation' the <begin>
Examples:
| begin
| [Today]
| [Today + 1]

How to fix this problem with assertEquals in Junit?

Please help me with the following problem, My Junit test fails because my output is
"09:39:43.704 [main] INFO by.iba.gomel.ShapeController - 145"
But i need just "145" ShapeController.LOGGER.info("{}", ShapeController.sum);
#Test
public void testSumma() {
final Shape[] newShapes = new Shape[5];
ShapeController.initializeArray(newShapes);
ShapeController.summa(newShapes);
Assert.assertEquals("these objects should be equal", "145", this.log.getLog());
}
If you are not changing the log format and the class name you can use this.log.getLog().split("ShapeController - ")[1].
But be wary of such hard-coded things. Anyways if you change something this test case will break and notify you.
You can use Java Library such as Hamcrest to make an assertion in a sentence if it ends with the number or word, such as 1 :
assertThat("myStringOfNote", endsWith("Note"))
This can be translated into your use case as :
assertThat(this.log.getLog(), endsWith("145"))

Getting different results for getStackTrace()[2].getMethodName()

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

How make JUnit print assertion results

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

Android Test Project JUnit Failure Trace Not Showing Expected + Actual

I'm writing some tests for an Android 2.3.3 project, using the Android JUnit Test runner, and I'm seeing some weird results in the failure traces on assertions. Here's a simple example:
import junit.framework.TestCase;
public class TU_Test extends TestCase {
public void testStuff() {
assertEquals("aft", "af");
}
}
The assertion obviously fails, and here's the trace copied from Eclipse:
junit.framework.ComparisonFailure: expected:<...t> but was:<...>
at com.redprairie.test.TU_Test.testStuff(TU_Test.java:33)
at java.lang.reflect.Method.invokeNative(Native Method)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:169)
at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:154)
at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:529)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1448)
The displayed expected + actual are not very helpful... it seems to display the difference / missing characters between the two, but it would be much more helpful if I could see the full values of each. I'm normally (using JUnit 4 + not using the Android Test Runner) able to double click the failure trace in Eclipse and see a diff of the two results. Is there any way to achieve this using the Android Test Runner and it's JUnit 3 style tests? It's kind of a pain in the ass to always set breakpoints.
Thanks!
Have you tried catching ComparisonFailure? You can call getActual() and getExpected() on the exception object to find out the values.
Take a look at the following javadoc: http://kentbeck.github.com/junit/javadoc/4.10/org/junit/ComparisonFailure.html
Since I couldn't find a real solution to this, I ended up just wrapping the assertion and building the message myself like so:
private void _assertEquals(String expected, String actual) {
assertEquals("expected <" + expected + "> but was <" + actual + ">", expected, actual);
}

Categories