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

JavaJunit

Java Problem Overview


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

Java Solutions


Solution 1 - Java

Call return statement anytime your test is finished and passed.

Solution 2 - Java

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.

Solution 3 - Java

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

Solution 4 - Java

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.

Solution 5 - Java

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.

Solution 6 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEugeneView Question on Stackoverflow
Solution 1 - JavaHorcrux7View Answer on Stackoverflow
Solution 2 - JavaColinDView Answer on Stackoverflow
Solution 3 - JavaGroostavView Answer on Stackoverflow
Solution 4 - JavaSebastian KView Answer on Stackoverflow
Solution 5 - JavaAjayView Answer on Stackoverflow
Solution 6 - JavaDávid HorváthView Answer on Stackoverflow