JUnit4 fail() is here, but where is pass()? - java

There is a fail() method in JUnit4 library. I like it, but experiencing a lack of pass() method which is not present in the library. Why is it so?
I've found out that I can use assertTrue(true) instead but still looks unlogical.
#Test
public void testSetterForeignWord(){
try {
card.setForeignWord("");
fail();
} catch (IncorrectArgumentForSetter ex){
}
// assertTrue(true);
}

Call return statement anytime your test is finished and passed.

As long as the test doesn't throw an exception, it passes, unless your #Test annotation specifies an expected exception. I suppose a pass() could throw a special exception that JUnit always interprets as passing, so as to short circuit the test, but that would go against the usual design of tests (i.e. assume success and only fail if an assertion fails) and, if people got the idea that it was preferable to use pass(), it would significantly slow down a large suite of passing tests (due to the overhead of exception creation). Failing tests should not be the norm, so it's not a big deal if they have that overhead.
Note that your example could be rewritten like this:
#Test(expected=IncorrectArgumentForSetter.class)
public void testSetterForeignWord("") throws Exception {
card.setForeignWord("");
}
Also, you should favor the use of standard Java exceptions. Your IncorrectArgumentForSetter should probably be an IllegalArgumentException.

I think this question needs an updated answer, since most of the answers here are fairly outdated.
Firstly to the OP's question:
I think its pretty well accepted that introducing the "expected excepetion" concept into JUnit was a bad move, since that exception could be raised anywhere, and it will pass the test. It works if your throwing (and asserting on) very domain specific exceptions, but I only throw those kinds of exceptions when I'm working on code that needs to be absolutely immaculate, --most APIS will simply throw the built in exceptions like IllegalArgumentException or IllegalStateException. If two calls your making could potentitally throw these exceptions, then the #ExpectedException annotation will green-bar your test even if its the wrong line that throws the exception!
For this situation I've written a class that I'm sure many others here have written, that's an assertThrows method:
public class Exceptions {
private Exceptions(){}
public static void assertThrows(Class<? extends Exception> expectedException, Runnable actionThatShouldThrow){
try{
actionThatShouldThrow.run();
fail("expected action to throw " + expectedException.getSimpleName() + " but it did not.");
}
catch(Exception e){
if ( ! expectedException.isInstance(e)) {
throw e;
}
}
}
}
this method simply returns if the exception is thrown, allowing you to do further assertions/verification in your test.
with java 8 syntax your test looks really nice. Below is one of the simpler tests on our model that uses the method:
#Test
public void when_input_lower_bound_is_greater_than_upper_bound_axis_should_throw_illegal_arg() {
//setup
AxisRange range = new AxisRange(0,100);
//act
Runnable act = () -> range.setLowerBound(200);
//assert
assertThrows(IllegalArgumentException.class, act);
}
these tests are a little wonky because the "act" step doesn't actually perform any action, but I think the meaning is still fairly clear.
there's also a tiny little library on maven called catch-exception that uses the mockito-style syntax to verify that exceptions get thrown. It looks pretty, but I'm not a fan of dynamic proxies. That said, there syntax is so slick it remains tempting:
// given: an empty list
List myList = new ArrayList();
// when: we try to get the first element of the list
// then: catch the exception if any is thrown
catchException(myList).get(1);
// then: we expect an IndexOutOfBoundsException
assert caughtException() instanceof IndexOutOfBoundsException;
Lastly, for the situation that I ran into to get to this thread, there is a way to ignore tests if some conidition is met.
Right now I'm working on getting some DLLs called through a java native-library-loading-library called JNA, but our build server is in ubuntu. I like to try to drive this kind of development with JUnit tests --even though they're far from "units" at this point--. What I want to do is run the test if I'm on a local machine, but ignore the test if we're on ubuntu. JUnit 4 does have a provision for this, called Assume:
#Test
public void when_asking_JNA_to_load_a_dll() throws URISyntaxException {
//this line will cause the test to be branded as "ignored" when "isCircleCI"
//(the machine running ubuntu is running this test) is true.
Assume.assumeFalse(BootstrappingUtilities.isCircleCI());
//an ignored test will typically result in some qualifier being put on the results,
//but will also not typically prevent a green-ton most platforms.
//setup
URL url = DLLTestFixture.class.getResource("USERDLL.dll");
String path = url.toURI().getPath();
path = path.substring(0, path.lastIndexOf("/"));
//act
NativeLibrary.addSearchPath("USERDLL", path);
Object dll = Native.loadLibrary("USERDLL", NativeCallbacks.EmptyInterface.class);
//assert
assertThat(dll).isNotNull();
}

I was looking for pass method for JUnit as well, so that I could short-circuit some tests that were not applicable in some scenarios (there are integration tests, rather than pure unit tests). So too bad it is not there.
Fortunately, there is a way to have a test ignored conditionally, which actually fits even better in my case using assumeTrue method:
Assume.assumeTrue(isTestApplicable);
So here the test will be executed only if isTestApplicable is true, otherwise test will be ignored.

There is no need for the pass method because when no AssertionFailedException is thrown from the test code the unit test case will pass.
The fail() method actually throws an AssertionFailedException to fail the testCase if control comes to that point.

I think that this question is a result of a little misunderstanding of the test execution process. In JUnit (and other testing tools) results are counted per method, not per assert call. There is not a counter, which keeps track of how many passed/failured assertX was executed.
JUnit executes each test method separately. If the method returns successfully, then the test registered as "passed". If an exception occurs, then the test registered as "failed". In the latter case two subcase are possible: 1) a JUnit assertion exception, 2) any other kind of exceptions. Status will be "failed" in the first case, and "error" in the second case.
In the Assert class many shorthand methods are avaiable for throwing assertion exceptions. In other words, Assert is an abstraction layer over JUnit's exceptions.
For example, this is the source code of assertEquals on GitHub:
/**
* Asserts that two Strings are equal.
*/
static public void assertEquals(String message, String expected, String actual) {
if (expected == null && actual == null) {
return;
}
if (expected != null && expected.equals(actual)) {
return;
}
String cleanMessage = message == null ? "" : message;
throw new ComparisonFailure(cleanMessage, expected, actual);
}
As you can see, in case of equality nothing happens, otherwise an excepion will be thrown.
So:
assertEqual("Oh!", "Some string", "Another string!");
simply throws a ComparisonFailure exception, which will be catched by JUnit, and
assertEqual("Oh?", "Same string", "Same string");
does NOTHING.
In sum, something like pass() would not make any sense, because it did not do anything.

Related

Best way to test a method containing a try/catch block in JUnit

I have the following method. The method converts the contents of a json string by using the Jackson ObjectMapper. If the json is malformed the stack trace is printed and the object is set to null:
public ObjectTransferData extractJacksonObjectsFromFile(String json) {
ObjectTransferData objectTransferData;
try {
objectTransferData = objectMapper.readValue(json, ObjectTransferData.class);
} catch (Exception e) {
e.printStackTrace();
objectTransferData = null;
}
return objectTransferData;
}
I wrote the JUnit unit test for a possible malformed json string like this:
#Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectNull(){
String malformedJson = "{";
ObjectTransferData result = myService.extractJacksonObjectsFromFile(malformedJson);
assertNull(result);
}
This test passes. But it is also printing the e.printStackTrace() into my terminal which is obscuring the actual important logs during test execution. It can be confusing for the reader of the test execution.
I am wondering how to resolve this issue. I came up with these ideas:
Remove the try/catch and just throw the exception. This would allow me to just write the test like this and not get a stacktrace into the console.
#Test
public void testExtractJacksonObjectsFromFile_malformedJson_expectException(){
String malformedJson = "{";
assertThrows(Exception.class, () ->
objectImportService.extractJacksonObjectsFromFile(malformedJson)
);
}
However the disadvantage is that the real application now throws this Exception and does not gracefully fail by handling it through a catch block.
Somehow suppress the exception logging for the tests. But this could lead to supressed logs for actual errors during the test execution.
This question is somewhat related, but does not fully answer my question.
I could just redirect all testing stacktraces to a file like this, but I don't want to redirect actual exceptions during test execution.
Telling a specific test to not print stacktrace would be ideal.
You need to decide whether you want to change application behaviour (and report the exception as you already suggested) or to keep the behaviour and return a null.
But there is a third option, especially since you are after unit tests:
Split the functionality of your method into two parts:
the part that parses the JSON and throws an exception
a wrapper function that catches the exception, prints it to stdout and returns null
Your unit test could now test 1) while the application uses 2).
If you do not like this either, you could - in your unit test - redirect stdout into some temporary ByteArrayStream before calling the exception throwing stuff, then not only check if null is returned but also if the byte array received the correct data.

Writing unit test for #Nonnull annotated parameter

I have a method like this one:
public void foo(#Nonnull String value) {...}
I would like to write a unit test to make sure foo() throws an NPE when value is null but I can't since the compiler refuses to compile the unit test when static null pointer flow analysis is enabled in IDE.
How do I make this test compile (in Eclipse with "Enable annotation-based null analysis" enabled):
#Test(expected = NullPointerException.class)
public void test() {
T inst = ...
inst.foo(null);
}
Note: In theory the static null pointer of the compiler should prevent cases like that. But there is nothing stopping someone from writing another module with the static flow analysis turned off and calling the method with null.
Common case: Big messy old project without flow analysis. I start with annotating some utility module. In that case, I'll have existing or new unit tests which check how the code behaves for all the modules which don't use flow analysis yet.
My guess is that I have to move those tests into an unchecked module and move them around as I spread flow analysis. That would work and fit well into the philosophy but it would be a lot of manual work.
To put it another way: I can't easily write a test which says "success when code doesn't compile" (I'd have to put code pieces into files, invoke the compiler from unit tests, check the output for errors ... not pretty). So how can I test easily that the code fails as it should when callers ignore #Nonnull?
Hiding null within a method does the trick:
public void foo(#NonNull String bar) {
Objects.requireNonNull(bar);
}
/** Trick the Java flow analysis to allow passing <code>null</code>
* for #Nonnull parameters.
*/
#SuppressWarnings("null")
public static <T> T giveNull() {
return null;
}
#Test(expected = NullPointerException.class)
public void testFoo() {
foo(giveNull());
}
The above compiles fine (and yes, double-checked - when using foo(null) my IDE gives me a compile error - so "null checking" is enabled).
In contrast to the solution given via comments, the above has the nice side effect to work for any kind of parameter type (but might probably require Java8 to get the type inference correct always).
And yes, the test passes (as written above), and fails when commenting out the Objects.requireNonNull() line.
Why not just use plain old reflection?
try {
YourClass.getMethod("foo", String.class).invoke(someInstance, null);
fail("Expected InvocationException with nested NPE");
} catch(InvocationException e) {
if (e.getCause() instanceof NullPointerException) {
return; // success
}
throw e; // let the test fail
}
Note that this can break unexpectedly when refactoring (you rename the method, change the order of method parameters, move method to new type).
Using assertThrows from Jupiter assertions I was able to test this:
public MethodName(#NonNull final param1 dao) {....
assertThrows(IllegalArgumentException.class, () -> new MethodName(null));
Here design by contract comes to picture. You can not provide null value parameter to a method annotated with notNull argument.
You can use a field which you initialize and then set to null in a set up method:
private String nullValue = ""; // set to null in clearNullValue()
#Before
public void clearNullValue() {
nullValue = null;
}
#Test(expected = NullPointerException.class)
public void test() {
T inst = ...
inst.foo(nullValue);
}
As in GhostCat's answer, the compiler is unable to know whether and when clearNullValue() is called and has to assume that the field is not null.

Java test with expected = exception fails with assertion error [duplicate]

This question already has answers here:
Why won't this Expect Exception Junit Test Work?
(2 answers)
Closed 6 years ago.
I'm having an issue with a test case.
The method being tested has a try / catch that catches a MalformedURLException but during testing I get a failure due to a Junit AssertionError that expects a MalformedURLException. But I can't find out what it is actually throwing! Here is my code (created as a MWE in eclipse).
My method that I want to test
public void throwMalFormedURLException(){
String s = new String("www.google.com");
try{
url = new URL(s);
}catch (Exception e){
e.printStackTrace();
e.getClass();
e.getCause();
}
}
the test method
#Test (expected = MalformedURLException.class)
public void testThrowMalFormedURLException() {
MWE testClass = new MWE();
testClass.throwMalFormedURLException();
System.out.println("End of test");
}
This is the output in the console
End of test error details are: java.net.MalformedURLException: no protocol: www.google.com
at java.net.URL.(URL.java:593)
at java.net.URL.(URL.java:490)
at java.net.URL.(URL.java:439)
at MWE.throwMalFormedURLException(MWE.java:12)
at testMWE.testThrowMalFormedURLException(testMWE.java:12)
In the Junit console it says :
java.lang.AssertionError: Expected exception: Java.net.MalformedURLException
But the Junit is reporting failure, even though the console is telling me I've got a MalformedURLException.
What am I doing wrong with this test ?
Thanks for your thoughts.
David
You are catching the exception and therefore it is not being thrown.
If your intent is to test that you are capturing the exception and relaying it back to the 'user' properly, you should create tests for that specifically. You probably don't want UI elements in your unit tests* so this is a place where abstraction and DI have a lot of value. One simple approach is to create a mock object that will listen for the error message and mark a flag when the message is received. Your unit test trigger the error and then pass if the flag is set. You should also have a negative test or assert that the flag is not set prior to throwing the exception.
*Testing the UI is also a good idea but it can be a little slow. There are various tools for automating that. It generally falls in to a different phase of testing. You really want the unit tests to be really fast so that you can run them very frequently.
You have written production code that simply isn't testable. And more specifically: this code doesn't have any "programmatically" observable side effects in the first place.
Meaning: when you write "production code", the code within a method can do three things that could be observed:
Make method calls on objects that are fields of the class under test
Return some value
Throw an exception
For each of these options, you might be able to write testing code:
Using dependency injection, you can put a mocked object into your class under test. And then you can check that the expected methods are invoked on your mock object; with the parameter that you would expect.
You compare the result you get from calling that method with some expected value
You use expected to ensure that a specific exception was thrown
When you look at your code; you can see: it does none of that. It only operates on objects that are created within the method. It doesn't return any value. And, most importantly: it doesn't throw an exception!
Long story short: a caught exception isn't "leaving" the method. It is caught there, and the method ends normally. The fact that you print details about the caught exception doesn't change that.
So, the first thing you have to do: remove the whole try/catch from your production code!
And, if you want to have a more specific test, you can do something like:
#Test
public void testException() {
try {
new MWE().throwMalFormedURLException();
fail("should have thrown!");
} catch ( MalFormedURLException me ) {
assertThat(me.getMessage(), containsString("whatever"));
}
The above:
fails when no exception is thrown
fails when any other exception than MalFormedURLException is thrown
allows you to check further properties of the thrown exception
This is a valid test failure. The test asserts that calling throwMalFormedURLException() will throw MalformedURLException, but since you're catching the exception, it doesn't throw it, so the test fails.

Junit using groovy expected exception

I have Spring boot application. I use Junit+Mockito to unit test it. All the test cases were written using Java. I recently made a decision to write test cases using Groovy though the application code will remain in Java.
I encountered a weird scenario while testing expected exceptions.
Scenario 1: Testing Expected exception using Junit + Groovy (without shouldFail):
#Test(expected = NoResultException.class)
void testFetchAllNoResultsReturned() throws Exception {
List<Name> namesLocal = null;
when(Service.fetchAllNames(id)).thenThrow(
new NoResultException(""))
namesLocal = (service.fetchAllNames(id)
assert(namesLocal==null)
verify(service, times(1)).fetchAllNames(id)
}
As per the above test case, service.fetchAllNames call should throw a NoResultException. This aspect of testing seems to work well. However, the assert and verify after that are not called. As soon as the exception is encountered, the method execution stops. However, my earlier test case written in Java worked perfectly well. This issue happened only after I switched to Groovy.
After doing some Google search I found there is a method called shouldFail provided by GroovyTestCase class which can be used for this scenario as per this link. And it did resolve my issue.
Scenario 2: Testing Expected exception using Junit + Groovy (with shouldFail ):
#Test
void testFetchAllNoResultsReturned() throws Exception {
List<Name> namesLocal = null;
when(Service.fetchAllNames(id)).thenThrow(
new NoResultException(""))
shouldFail(NoResultException.class) {
namesLocal = (Service.fetchAllNames(id)
}
assert(namesLocal==null)
verify(Service, times(1)).fetchAllNames(id)
}
My doubt is, is this how it is supposed to work or am I missing something. If this is how it is supposed to work, is there any reason behind Groovy doing it this way? I tried to look for reasons on the internet but I couldn't get many leads.
However, the assert and verify after that are not called. As soon as the exception is encountered, the method execution stops. However, my earlier test case written in Java worked perfectly well.
Given this code in java:
#Test(expected = NoResultException.class)
void testFetchAllNoResultsReturned() throws Exception {
List<Name> namesLocal = null;
when(Service.fetchAllNames(id)).thenThrow(
new NoResultException(""))
namesLocal = (service.fetchAllNames(id)
....
}
Irrespective of what you have after service.fetchAllNames(id), the call will throw an Exception and the test case ends there. Since you have an expected exception defined, the test case will pass. So the assert and verify after this line of code are never executed in java.
I am not familiar with groovy but from the documentation it looks like your second example using shouldFail is the correct way to test for exceptions in groovy. The shouldFail does not terminate the program - so its similar to putting your method call in a try catch in java

What is the difference between assert object!=null and Assert.assertNotNull(object)?

What is the difference between following two blocks of code?
#Test
public void getObjectTest() throws Exception {
Object object;
//Some code
Assert.assertNotNull(object);
}
AND
#Test
public void getObjectTest() throws Exception {
Object object;
//Some code
assert object!=null;
}
I do understand that Assert.AssertNotNull is a function call from TestNG and assert is a key word of Java ( introduced in Java 1.4 ). Are there any other differences in these two ? e.g. working, performance etc
Well the first case uses the Assert class from your testing framework and is the right way to go, since TestNG will report the error in an intelligent way.
You can also add your own message to the test:
Assert.assertNotNull(object, "This object should not be null");
The second case uses the assert keyword - it will give you a failure but the stack trace may or may not be understandable at a glance. You also need to be aware that assertions may NOT be enabled.
Talking about Performance:
assert object!=null; is a single java statement but Assert.assertNotNull(object) will result in calling of Multiple functions of TestNG, so w.r.t. performance assert object!=null; will be slightly better.
Yes, there is: the assert keyword needs to be enabled using the -ea flag, like
java -ea MyClass
The assert can therefor be turned on and off without any changes to the code.
The Assert class will always work instead. So, if you're doing testing, use the Assert class, never the assert keyword. This might give you the idea all your tests are passing, and while actually they don't assert anything. In my 10+ years of coding, I've never seen anyone enable assertions except Jetbrains, so use Assert instead. Or better, use Hamcrest.
The difference is basically the lack of assert keyword.
This is the source from testng:
static public void assertNotNull(Object object) {
assertNotNull(object, null);
}
static public void assertNotNull(Object object, String message) {
assertTrue(object != null, message);
}
Please note that the OP used the testng tag!
This is not JUnit's Assert!
Some info about java's assert keyword: assert

Categories

Resources