Question

I've learnt how to catch an exception in Junit testing. but now I want to loop through arguments which can cause the exception {null, Object.class} currently the test runs for the first loop then exists with a pass and does not check the next loop argument.

@Rule
public ExpectedException ee;

public ClassTest() {
    this.ee = ExpectedException.none();
}

/**
 * Test of isCompramised method.
 */
@Test
public void testIsCompramised2() {
    System.out.println("isCompramised Exception");
    Class<?>[] c = {null, Object.class};
    for (Class<?> class1 : c) {
        MyClass instance = new MyClass();

        ee.expect(IllegalArgumentException.class);
        boolean result = instance.isCompramised(class1);
        fail("Exception should have been thrown");

    }
}

So I tried this, it completes the for loop but all the expected exceptions fail as i think Try Catch now steals the exception.

/**
 * Test of isCompramised method, of class MyClass.
 */
@Test
public void testIsCompramised2() {
    System.out.println("isCompramised Exception");
    Class<?>[] c = {null, Object.class};
    for (Class<?> class1 : c) {
        MyClass instance = new MyClass();
        try{
            ee.expect(IllegalArgumentException.class);
            boolean result = instance.isCompramised(class1);
            fail("Exception should have been thrown");
        } catch (Exception e){
            continue;
        }
    }
}

Suggestions please?

Is this correct?

try{     
    boolean result = instance.isCompramised(class1);
    fail("Exception should have been thrown");
} catch (Exception e){
    AssertTrue(e instanceOf IllegalArgumentException);
    continue;
}
Was it helpful?

Solution

I would go with something like that:

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

import java.util.Arrays;


@RunWith(Parameterized.class)
public class Foo {

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Parameter
    public Class<?> input;

    /**
     * Test of isCompramised method, of class MyClass.
     */
    @Test
    public void testIsCompramised() {
        this.expectedException.expect(IllegalArgumentException.class);
        final MyClass instance = new MyClass();
        instance.isCompramised(input);
    }

    @Parameters(name = "test for {0}")
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] { {null}, {Object.class} });
    }
}

(or two test methods, one for null and one for Object)


EDIT: some complements (see comments)

The methods annotated with @Parameters returns an Iterable containing Object[]. Each of those Object[] is bound to a @Parameter annotated field (using the value of @Parameter as index [default: 0]). JUnit Parameterized runner will iterate over the @Parameters data and for each array, set fields values and then run every tests in the class.

See also: Parameterized javadoc

OTHER TIPS

Catching and checking the exception manually within the loop, instead of using expect, may be the way to go there. Your "is this correct" code block should work if placed within the loop.

As this is the first google result when searching I want to add my solution.

In my example Datum throws an exception if the date gets invalid arguments in the constructor.

To test this I wanted to test that the constructor will not accept invalid input and throw an exception.

I test a range of example-cases that should be rejected with a for loop.

To test that the loop threw an exception in every iteration I simply added a boolean variable that was set true in a catch for this exact exception on every iteration, if the variable was false at the end of the iteration then a runtime exception would be thrown that will let the test fail.

I think this is far easier to read for teammembers afterwards without any extravagant knowledge for junit tests. It is much easier to use for beginners as well.

package übungen.blatt_01;

import org.junit.Test;

public class DatumTest {

@Test
public void testConstructor() throws Exception {
    for(int jahr = 1801; jahr <2010; jahr++) {
        for(int monat = 1; monat <= 12; monat++) {
            for(int tag = 1; tag <= Datum.getMonatslänge(monat, jahr); tag++) {
                try{
                    new Datum(tag,monat,jahr);
                }
                catch(Exception e){System.out.println(tag+","+monat+","+jahr); e.printStackTrace(); return;}
            }
        }
    }
}

@Test
public void testAllExclusive() {
    boolean failAsExpected = false;
    for(int jahr = 1801; jahr <2010; jahr++) {
        for(int monat = 12+1; monat <= 24; monat++) {
            for(int tag = 32; tag <= 60; tag++) {
                failAsExpected=false;
                try {
                    testConstructorErrors(tag,monat,jahr);
                }catch(DateOutOfRangeException e){
                    failAsExpected=true;
                }
                if(!failAsExpected)
                    throw new RuntimeException("test failed");
            }
        }
        for(int monat = -1; monat >= -24; monat--) {
            for(int tag = -1; tag >= -60; tag--) {
                try {
                    testConstructorErrors(tag,monat,jahr);
                }catch(DateOutOfRangeException e){
                    failAsExpected=true;
                }
                if(!failAsExpected)
                    throw new RuntimeException("test failed");
            }
        }
    }
}

public void testConstructorErrors(int tag, int monat, int jahr) {
    //put additional code here to increase readability of the test loop
    new Datum(tag,monat,jahr);
}
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top