检查方法在应用于值列表的任何元素时是否抛出异常

时间:2013-12-08 12:34:40

标签: java exception junit

我想为解析器编写单元测试,并希望检查它是否正确地为列表中的所有输入字符串抛出异常。根据我的理解,使用 JUnit 的标准方法是为每个案例编写一个单独的测试方法:

public final class ParseFailureTest1 {
    @Test(expected = ParseException.class)
    public void testParseFailure1() throws Exception {
        Parser.parse("[1 2]"); // Missing comma
    }

    @Test(expected = ParseException.class)
    public void testParseFailure2() throws Exception {
        Parser.parse("[1, 2,]"); // Additional commas
    }
}

但是,由于我想将相同的测试应用于20或50个不同的字符串,这似乎是不切实际的。

另一种方法是使用catch块明确检查异常:

public final class ParseFailureTest2 {
    @Test
    public void testParseFailure() throws Exception {
        List<String> documents = Arrays.asList(
            "[1 2]", // Missing comma
            "[1, 2,]"); // Additional commas

        for (String document : documents) {
            try {
                Parser.parse(document);

                throw new AssertionError("Exception was not thrown");
            } catch (ParseException e) {
                // Expected, do nothing.
            }
        }
    }
}

但是这很容易出错,我不会得到任何关于预期的异常的信息,如果抛出了不同的异常,它将被视为测试错误,而不是失败。

我的解决方案是使用类似于以下expectException的方法:

public final class ParseFailureTest3 {
    @Test
    public void testParseFailure() throws Exception {
        List<String> documents = Arrays.asList(
            "[1 2]", // Missing comma
            "[1, 2,]"); // Additional commas

        for (final String document : documents) {
            expectException(ParseException.class, new TestRunnable() {
                @Override
                public void run() throws Throwable {
                    Parser.parse(document);
                }
            });
        }
    }

    public static void expectException(Class<? extends Throwable> expected, TestRunnable test) {
        try {
            test.run();
        } catch (Throwable e) {
            if (e.getClass() == expected) {
                return; // Expected, do nothing.
            } else {
                throw new AssertionError(String.format("Wrong exception was thrown: %s instead of %s", e.getClass(), expected), e);
            }
        }

        throw new AssertionError(String.format("Expected exception was not thrown: %s", expected));
    }

    public interface TestRunnable {
        void run() throws Throwable;
    }
}

在JUnit框架或相关库中是否存在用于此目的的方法,或者您是否会针对该问题提出不同的方法(或我拒绝的方法之一)?

3 个答案:

答案 0 :(得分:3)

使用JUnit4进行参数化测试功能。以下代码应该可以使用。

import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(value = Parameterized.class)
public class ParseTest {

    private String parseValue;

    public ParseTest(String parseValue) {
        this.parseValue = parseValue;
    }

    @Parameters
    public static Collection<Object[]> data() {
        Object[][] data = new Object[][] { { "[1 2]" }, { "[1,2,]" } };
        return Arrays.asList(data);
    }

    @Test(expected = ParseException.class)
    public void testParseFailure1() throws Exception {
        Parse.parse(parseValue);
    }

}

有关详细信息,请参阅http://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/

答案 1 :(得分:2)

使用fail()方法:

@Test
public void testParseFailure() throws Exception {
    List<String> documents = Arrays.asList(
        "[1 2]", // Missing comma
        "[1, 2,]"); // Additional commas

    for (String document : documents) {
        try {
            Parser.parse(document);
            fail("Parsing " + document + " should have thrown a ParseException");
        } 
        catch (ParseException e) {
            // Expected, do nothing.
        }
    }
}

答案 2 :(得分:0)

如果您关心在异常中获取正确的消息,那么这是另一种选择,保留前一个答案的fail想法。

public final class ParseFailureTest {
  @Test
  public void testParseFailure() throws Exception {
      Map<String, String> documents = new LinkedHashMap<String,String>();
      documents.put("[1 2]", "Missing comma");
      documents.put("[1, 2,]", "Additional commas");

      for (Entry<String,String> entry : documents.entrySet()) {
          try {
              Parser.parse(entry.getKey());
              fail("Parsing " + entry.getKey() + 
                      " should have thrown a ParseException");
          } catch (ParseException e) {
              assertEquals(entry.getValue(), e.getMessage());
          }
      }
  }
}