Are AssertionErrors forbidden if I want to use JUnit? - java

I have a method that during a specific point of processing it expects that certain invariants are kept.
To keep this trivial let's say that at point X during the code processing the variable high and the variable low MUST be divisible.
So in the code I do:
if(high % low != 0){
throw new AssertionError("Invalid state of low and high [low = "+ low+ ", high=" + high+"]");
}
During unit testing with JUnits I had a test case to test for this.
So I did:
try {
//At this point I know for sure that the low and high are not divible so process() should throw an Assertion Error
process();
fail();
}
catch(AssertionError e){
}
But the test case was green!
But I realised that junit raises an assert error due to fail but I catch it and as a result the test case is pass instead of failed.
From my point of view the proper error to raise in my code is also AssertionError and not some generic e.g. IllegalArgumentsException
So is there a way to fix this so that the test case works or should I not be using the AssertionError in my code in the first place? If this is the case, what exception should I be raising?

You should not have a try-catch block in a unit test. If you expect an exception use an annotation:
#Test(expected=Exception.class)
public void youTestMethod() {
...
}
You will have to use a different exception such as IllegalArgumentsException because JUnit uses AssertionError internally. I find IllegalArgumentsException more descriptive of what actually went wrong.

boolean shouldFail = false;
try {
callTheMethod();
shouldFail = true;
}
catch (AssertionError e) {
// expected
}
if (shouldFail) {
fail();
}
But if the condition is an invariant, then it should always be true, and the AssertionError should thus never be thrown, and you should thus not even be able to unit test it. If you're able to test it, it means that the invariant is not really an invariant, and that the condition might be true depending on the sequence of calls or on the arguments provided. You should thus prefer an IllegalStateExcetion over the AssertionError.

> should I not be using the AssertionError in my code in the first place?
No JUnit is using AssertionError and its decendants to tell the junit-runner that a test has failed. (Simmilar applies to .net NUnit-runner)
> If this is the case, what exception should I be raising?
I would use one of the generic Exceptoin like IllegalArgumentsException or create my own Exception

Yes, there is a conflict between your code and JUnit, but it's easy to get around.
When you write a JUnit test case, as you've already deduced, an AssertionError is thrown when the test case has failed.
To let JUnit know that your test case has passed, the test code should NOT throw an AssertionError on any other Exception/Error for that matter.
There will be two test cases (at least) -
A. high and low are exactly divisible - the test case code doesn't throw an AssertionError.
//test case setup
yourClass.callYourMethod(4,2);
//verification
Here, if the test case behaves correctly, there is no AssertionError and JUnit knows it has passed.
B. high and low are not exactly divisible - the code should throw AssertionError but the test case should not.
boolean failed;
try {
//test case setup
yourClass.callYourMethod(4,2);
failed = true;
} catch (AssertionError e) {
failed = false;
}
if (failed) {
fail();
}

Related

Usage of throws command in java

I know questions like this are everywhere, but I read a lot of things about this, and I still can't understand what the "throws" command do. I will be more specific now:
So, one of the examples I saw was this one, with the following code:
public class CatchThrow {
private static void throwsMethod() throws NumberFormatException {
String intNumber = "5A";
Integer.parseInt(intNumber);
}
private static void catchMethod() {
try {
throwsMethod();
} catch (NumberFormatException e) {
System.out.println("Convertion Error");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
catchMethod();
}
}
Now, if I remove the "throws NumberFormatException" from the "throwsMethod" method, the program will run the same, and will give the same results. Actually, every example with the throws command that I saw did the same, so I can't really understand why use it.
I'm using the Eclipse IDE, version 4.7.2.
Normally your function exits at the end of the function or the return statement.
However, a function can also exit when it reaches a throw statement. If the exception subclasses Exception, the caller of the function must surround the function call with a try { } catch { } block. If the exception subclasses RuntimeException you may optionally surround the function call in a try catch block.
If you look at the JavaDoc for NumberFormatException: https://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html will see it subclasses RuntimeException. This means your try-catch block is optional. The difference between the two program is this: With the try-catch block you will get Convertion Error printed to the console, without it, you will see the full stack trace. This is often called "swallowing the exception".
So basically, if an exception occurs and you don't want to handle that exception there, in that case you use the 'throw' keyword to simply just throw the exception if occurs.
Example: Here, in throwsMethod(), you are not taking care of the Exception Handling i.e. not using the try(), catch() blocks, you are just throwing it if there occurs any Exception. And you will land in catch() block if exception occurs in your throwsMethod().
To get better idea, you should read checked & Unckecked exceptions in Java. For Checked exceptions (happen at compile-time), we use 'throw' keyword and for Unchecked (Run-time), we use try() catch().
Example: NumberFormatException is an Unchecked exception, IOException is a Checked exception.
Read this for reference: https://www.geeksforgeeks.org/checked-vs-unchecked-exceptions-in-java/

JaCoCo branch coverage try with resources

I have a method that I am trying to unit-test. I cannot post the actual code, but it looks like this:
public int getTotal() throws MyException {
int total = 0;
try (ExternalResource externalResource = ExternalService.getResource()) {
try (OtherExternal otherResource = externalResource.getOtherResource()) {
if (someCondition) {
total = otherResource.getTotal();
}
}
}
}
JaCoCo is telling me that I am missing 4/8 branches on each of the try-with-resource blocks. I am testing that someCondition is true and someCondition is false, and JaCoCo shows that block completely covered.
I read this question, and I understand from the accepted answer that the issue is in how the byte code is generated.
I would like to be able to better understand how to identify the various branches that are generated, and then I can make a better judgement on wether to test them or not (are they unreachable, etc).
Per the change history in version 0.8.2:
Branches and instructions generated by javac 11 for try-with-resources statement are filtered out
I've tested this out locally using openjdk java8, and my try-with-resources now reports 100% branch coverage (even though the IOException is never thrown in my tests).
While it is good to test this behavior out, there are times when you can't easily reproduce such exceptions. For instance, in a method that just returns an open port:
public int getOpenPort() {
try (ServerSocket boundSocket = new ServerSocket(0)) {
return boundSocket.getLocalPort();
}
}
I know of no simple way to force this code to throw IOException without adding a bunch of confusing and unnecessarily complicated code, just to pass a branch coverage check. Luckily, the new (v0.8.2) jacoco library gives this method 100% coverage with a single test just calling Assert.assertNotEquals(0, portChecker.getOpenPort());.
You have to test every Exception and every condition. But JaCoCo sometimes failed to identify correctly what is covered or not.

The console in Eclipse (Java) does not output things in the correct/chronological order

Why is the output not in the correct order for the following test code:
public static void main(String[] args) {
boolean test = false;
try {
assert test: "will fail with -ea enabled in VM args" ;
} catch (AssertionError e) {
e.printStackTrace();
System.out.println("idk why you would use this but...");
}
System.out.println(test + " sneaks in between");
}
run this with "-ea" enabled in the VM arguments (run config)
randomly the output is either:
java.lang.AssertionError: will fail with -ea enabled in VM args
at Main.main(Main.java:31)
FOO
BAR
(should happen) or:
java.lang.AssertionError: ERROR
FOO
BAR
at Main.main(Main.java:31)
(should not happen) and sometimes:
java.lang.AssertionError: ERROR
FOO
at Main.main(Main.java:31)
BAR
I was messing around with "assert" when this happened. I know the code is complete nonsense but it may also happen with other setups.
Seconldy consoles are not really used too much in many programs as an official thing, mostly for debugging. But it is still weird.
Is this because the try catch is running on a different thread? or is the stuff happening so fast after eachother that one thing pushes out before the other thing?
I do notice adding a Thread.sleep(1); (which needs to be thrown or caught)
does make it always go in chronological order, so...
Why does it not print the code in chronological order?
printStackTrace() prints to the error out. How that chronologically lines up with the standard out is indeterminate. You can try calling flush() on System.out, but I can't assure you the result will ever be as you expect unless you specifically print the stack trace to standard out using one of the other available methods.

Detect failure in Code

Can anyone help me with my problem?
I test my program with Robotium in Junit.
My problem is:
When I detect there is a failure in junit, how can I use code to detect there is failure in program? So, I can continue run if no error occur? e.g. if no error, continue testing, else exit.
I suggest using Java's built-in assertions for your test. To create an assertion:
assert someBoolean : message;
For example:
assert (myValue == 3) : "myValue was " + myValue + ", should have been 3";
Assertions are disabled by default when running your program. To run your program with assertions, run it like this:
java -enableassertions MyClass
Then, if your program is running with this runtime option, whenever an assert is reached, the following happens:
If the boolean is true, the program will continue.
If it is false, an AssertionError is thrown with the specified message.
For example:
int myVar = 5;
assert (myVar == 3) : "myVar is " + myVar + " not 3";
results in
Exception in thread "main" java.lang.AssertionError: myVar is 5 not 3
IF assertions are enabled. Remember: all of that only happens when you enable asserts using -enableassertions or -ea. If you don't, the asserts are skipped.
When I detect there is a failure in junit, how can I use code to detect there is failure in program? So, I can continue run if no error occur? e.g. if no error, continue testing, else exit.
This doesn't make much sense. If you've got a failure in a JUnit test, that means there is a failure in your program. If no failure occurs, the unit testing will proceed to the next test automatically.
But maybe you are asking if you can do this:
// in some unit test
assert(....); // <<--- this test fails:
// Do something so that the unit test will continue to the next assertion ...
assert(....)
The answer is that you can't do that in any useful way:
The unit test framework can only report unit test failures that indicate that they have failed by terminating with an exception.
You could write a unit test to catch the exception that an assert(...) or fail(...) call throws and continue to the next assertion. But that would destroy all evidence of the previous unit test failure.
So if you want to be able to do the second assertion despite the first one failing, you need to make them separate testcases.
You might also be asking if there is a way to get the JUnit test runner to abort on the first failed unit test. The answer is yes that it is possible, but how you would do it would depend on the test runner you are using.
You can make assertions for a condition to be true or false-
assertTrue(soloObject.waitForActivity("Activity Name"));
Instead of wating for an activity you can use all the methods provided by robotium to make assertions example isTextFound("text"), isTextFound("text"), isCheckBoxChecked(index), etc.

Why does Throwable.getMessage() occasionally return null?

I have a method that sometimes throws an exception:
this.items[index] = element;
And I have a unit test that asserts that the exception that ought to be thrown is actually thrown:
try
{
doSomethingWithIndex(-1);
Assert.fail("should cause exception");
}
catch (IndexOutOfBoundsException expected)
{
Assert.assertNotNull(expected.getMessage());
}
This test runs as part of the continuous build and sometimes, occasionally it fails because getMessage() in fact returns null. Why would this happen? My code can never throw an exception with a null message.
EDIT
My original code example was misleading, the thrown exception is actually coming from directly indexing an array. I can reproduce the same behavior with a custom thrown exception though.
I added the suggested code:
catch (IndexOutOfBoundsException expected)
{
if (expected.getMessage() == null)
{
expected.printStackTrace();
}
Assert.assertNotNull(expected.getMessage());
}
The console output is missing the stack trace in addition to the cause. Here's the full output:
java.lang.ArrayIndexOutOfBoundsException
Found the answer on a similar question.
The JIT compiler will optimize away stack traces in certain exceptions if they happen enough.
The JVM flag -XX:-OmitStackTraceInFastThrow prevents this behavior and seems to fix the flickering unit tests.
Try printing stack trace of exception when it has null message. It's possible that some other code throws it. Like you actually accessing past array length.
You wrote that:
"My code can never throw an exception with a null message"
Are you yousing any 3rd party library? I assume standard java codes never throw exceptions like this above, but some pourly coded jar... :)

Categories

Resources