Java 我可以在一种测试方法中测试多个抛出的异常吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20603047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I test for multiple thrown exceptions in one test method?
提问by chillyistkult
I have a well specified interface and against that I write my JUnit tests:
我有一个明确指定的接口,并针对它编写了我的 JUnit 测试:
public interface ShortMessageService {
/**
* Creates a message. A message is related to a topic
* Creates a date for the message
* @throws IllegalArgumentException, if the message is longer then 255 characters.
* @throws IllegalArgumentException, if the message ist shorter then 10 characters.
* @throws IllegalArgumentException, if the user doesn't exist
* @throws IllegalArgumentException, if the topic doesn't exist
* @throws NullPointerException, if one argument is null.
* @param userName
* @param message
* @return ID of the new created message
*/
Long createMessage(String userName, String message, String topic);
[...]
}
As you can see the implementation can throw various exceptions for which I have to write tests. My current approach is to write one test method for one possible exception specified in the interface like this:
如您所见,该实现可能会抛出各种异常,我必须为其编写测试。我目前的方法是为接口中指定的一种可能的异常编写一种测试方法,如下所示:
public abstract class AbstractShortMessageServiceTest
{
String message;
String username;
String topic;
/**
* @return A new empty instance of an implementation of ShortMessageService.
*/
protected abstract ShortMessageService getNewShortMessageService();
private ShortMessageService messageService;
@Rule
public ExpectedException thrown = ExpectedException.none();
@Before
public void setUp() throws Exception
{
messageService = getNewShortMessageService();
message = "Test Message";
username = "TestUser";
topic = "TestTopic";
}
@Test
public void testCreateMessage()
{
assertEquals(new Long(1L), messageService.createMessage(username, message, topic));
}
@Test (expected = IllegalArgumentException.class)
public void testCreateMessageUserMissing() throws Exception
{
messageService.createMessage("", message, topic);
}
@Test (expected = IllegalArgumentException.class)
public void testCreateMessageTopicMissing() throws Exception
{
messageService.createMessage(username, message, "");
}
@Test (expected = IllegalArgumentException.class)
public void testCreateMessageTooLong() throws Exception
{
String message = "";
for (int i=0; i<255; i++) {
message += "a";
}
messageService.createMessage(username, message, topic);
}
@Test (expected = IllegalArgumentException.class)
public void testCreateMessageTooShort() throws Exception
{
messageService.createMessage(username, "", topic);
}
@Test (expected = NullPointerException.class)
public void testCreateMessageNull() throws Exception
{
messageService.createMessage(username, null, topic);
}
[...]
}
So for now I have to define a lot of test methods for that one method defined in the interface and that feels awkward. Can I combine all these exception tests in one test method or what is the best practice?
所以现在我必须为接口中定义的一个方法定义很多测试方法,这感觉很尴尬。我可以将所有这些异常测试组合在一种测试方法中,或者最佳实践是什么?
采纳答案by user2910265
Unfortunately, the @Test annotation doesn't allow for catching multiple exception types (api reference http://junit.sourceforge.net/javadoc/org/junit/Test.html).
不幸的是,@Test 注释不允许捕获多种异常类型(api 参考http://junit.sourceforge.net/javadoc/org/junit/Test.html)。
As a first option, I would advocate moving to TestNG. If your team won't allow that, there are few things you can do in JUnit.
作为第一个选择,我主张转向 TestNG。如果您的团队不允许这样做,那么您可以在 JUnit 中做一些事情。
Definitely use parameterized test cases so that you don't have to write one test function per test case (http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html). From here, there are a few options.
绝对使用参数化测试用例,这样您就不必为每个测试用例编写一个测试函数 ( http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html)。从这里开始,有几个选项。
Group your test data by exception types.
@Test (expected = IllegalArgumentException.class) public void testIllegalArgumentException(String username, String message, String topic) {} @Test (expected = NullPointerException.class) public void testNullPointerException(String username, String message, String topic) {}
Combine the exception types in your method signature. (This is what I recommend) Rough outline below ...
public void testException(String username, String message, String topic, Class<? extends Exception>[] expectedExceptionClasses) { try { // exception throwing code } catch (Exception e) { boolean found = false; for (Class<?> expectedException : expectedExceptions) { if (e instanceof expectedException) { found = true; } } if (found) { return; } } Assert.fail(); }
Put all of your tests under the umbrella Exception class (I have a feeling you don't want to do that.).
@Test (expected = Exception.class) public void testException(String username, String message, String topic) {}
按异常类型对测试数据进行分组。
@Test (expected = IllegalArgumentException.class) public void testIllegalArgumentException(String username, String message, String topic) {} @Test (expected = NullPointerException.class) public void testNullPointerException(String username, String message, String topic) {}
在方法签名中组合异常类型。(这是我推荐的)下面的粗略轮廓......
public void testException(String username, String message, String topic, Class<? extends Exception>[] expectedExceptionClasses) { try { // exception throwing code } catch (Exception e) { boolean found = false; for (Class<?> expectedException : expectedExceptions) { if (e instanceof expectedException) { found = true; } } if (found) { return; } } Assert.fail(); }
将所有测试放在伞形 Exception 类下(我感觉你不想这样做。)。
@Test (expected = Exception.class) public void testException(String username, String message, String topic) {}
回答by peter
It might not be the best idea to combine them all in one method, since you wouldn't really know which test case threw which exception.
将它们全部组合在一种方法中可能不是最好的主意,因为您不会真正知道哪个测试用例抛出了哪个异常。
For example, if you had the line
例如,如果你有这条线
messageService.createMessage(username, null, topic);
which should throw a NullPointerException
, but instead it threw an IllegalArgumentException
, you don't want that to count as a success.
应该抛出 a NullPointerException
,但它抛出了IllegalArgumentException
,你不希望这算作成功。
If you'd like to test all the exceptions of that method in one test case, then a good alternative would be to wrap each exception test in a try..catch block.
如果您想在一个测试用例中测试该方法的所有异常,那么一个不错的选择是将每个异常测试包装在 try..catch 块中。
For example, you could have
例如,你可以有
@Test
public void testCreateMessageExceptions() {
// test #1: a null message
try {
messageService.createMessage(username, null, topic);
// if it got this far, that's a problem!
fail();
} catch(NullPointerException e) {
// great, that's what it's meant to do! continue testing
} catch(Exception e) {
// if it threw the wrong type of exception, that's a problem!
fail();
}
// test #2: an empty user
try {
messageService.createMessage("", message, topic);
fail();
} catch(IllegalArgumentException e) {
} catch(Exception e) {
fail();
}
// ...
}