简体   繁体   中英

Junit handling expected exceptions in a loop

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM