我可以在一种测试方法中测试多个抛出的异常吗?

chi*_*ult 11 java testing junit exception-handling junit4

我有一个很好的指定接口,我写了我的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);

[...]

}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,实现可以抛出各种异常,我必须编写测试.我目前的方法是为接口中指定的一个可能的异常编写一个测试方法,如下所示:

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

[...]

}
Run Code Online (Sandbox Code Playgroud)

所以现在我必须为界面中定义的那个方法定义很多测试方法,这感觉很尴尬.我可以在一种测试方法中结合所有这些异常测试,还是最佳实践?

use*_*265 5

不幸的是,@ Test注释不允许捕获多个异常类型(api参考http://junit.sourceforge.net/javadoc/org/junit/Test.html).

作为第一种选择,我主张转向TestNG.如果您的团队不允许这样做,那么您在JUnit中可以做的事情很少.

绝对使用参数化测试用例,这样您就不必为每个测试用例编写一个测试函数(http://junit.sourceforge.net/javadoc/org/junit/runners/Parameterized.html).从这里,有几个选项.

  1. 按例外类型对测试数据进行分组.

    @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) {}
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在方法签名中组合异常类型.(这是我推荐的)下面的粗略轮廓......

    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();
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将所有测试放在一个Exception类的框架下(我有一种你不想这样做的感觉.).

    @Test (expected = Exception.class)
    public void testException(String username, String message, String topic) {}
    
    Run Code Online (Sandbox Code Playgroud)