Java JUnit 异常测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3083161/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:17:34  来源:igfitidea点击:

JUnit Exception Testing

javaunit-testingexceptionjunitjunit3

提问by InsertNickHere

Edit: Not JUnit 4 available at this time.

编辑:目前没有可用的 JUnit 4。

Hi there,

你好呀,

I have a question about "smart" exception testing with JUnit. At this time, I do it like this:

我有一个关于使用 JUnit 进行“智能”异常测试的问题。这个时候,我是这样做的:

public void testGet() {

    SoundFileManager sfm = new SoundFileManager();

        // Test adding a sound file and then getting it by id and name.
        try {
            SoundFile addedFile = sfm.addSoundfile("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
            SoundFile sf = sfm.getSoundfile(addedFile.getID());
            assertTrue(sf!=null);
            System.out.println(sf.toString());

            sf = sfm.getSoundfileByName("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
            assertTrue(sf!=null);
            System.out.println(sf.toString());
        } catch (RapsManagerException e) {
            System.out.println(e.getMessage());
        }

        // Test get with invalid id. 
        try {
            sfm.getSoundfile(-100);
            fail("Should have raised a RapsManagerException");
        } catch (RapsManagerException e) {
            System.out.println(e.getMessage());
        }

        // Test get by name with invalid name
        try {
            sfm.getSoundfileByName(new String());
            fail("Should have raised a RapsManagerException");
        } catch (RapsManagerException e) {
            System.out.println(e.getMessage());
        }

    }

As you can see, I need one try/catch block for each function that is supposed to throw an exception. It seems not to be a good way to do this - or is there no possibility to reduce the use of try/catch?

如您所见,对于每个应该抛出异常的函数,我都需要一个 try/catch 块。这似乎不是一个好方法 - 或者有没有可能减少 try/catch 的使用?

采纳答案by skaffman

I suggest that you need to break up testGetinto multiple separate tests. The individual try/catch blocks seem to be pretty independent of each other. You may also want to extract the common initialization logic into its own setup method.

我建议您需要分解testGet为多个单独的测试。各个 try/catch 块似乎彼此非常独立。您可能还想将公共初始化逻辑提取到其自己的设置方法中。

Once you have that, you can use JUnit4's exception annotation support, something like this:

一旦你有了它,你就可以使用 JUnit4 的异常注释支持,如下所示:

public class MyTest {

private SoundManager sfm;

@Before
public void setup() {
      sfm = new SoundFileManager();
}

@Test
public void getByIdAndName() {
  // Test adding a sound file and then getting it by id and name.
      SoundFile addedFile =              
      sfm.addSoundfile("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
      SoundFile sf = sfm.getSoundfile(addedFile.getID());
      assertTrue(sf!=null);
      System.out.println(sf.toString());

      sf = sfm.getSoundfileByName("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
      assertTrue(sf!=null);
      System.out.println(sf.toString());
}

@Test(expected=RapsManagerException.class)
public void getByInvalidId() {
      // Test get with invalid id. 
      sfm.getSoundfile(-100);
}

@Test(expected=RapsManagerException.class)
public void getByInvalidName() {
      // Test get with invalid id. 
      sfm.getSoundfileByName(new String());
}
}

回答by Péter T?r?k

With JUnit 4, you can use annotations instead. However, you should separate your test into 3 distinct methods for this to work cleanly. Note that IMHO catching an exception in the first scenario should be a failure, so I modified the catchblock accordingly.

在 JUnit 4 中,您可以改用注解。但是,您应该将您的测试分成 3 种不同的方法,以使其正常工作。请注意,恕我直言,在第一种情况下捕获异常应该是失败,因此我相应地修改了该catch块。

public void testGet() {
    SoundFileManager sfm = new SoundFileManager();

    // Test adding a sound file and then getting it by id and name.
    try {
        SoundFile addedFile = sfm.addSoundfile("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
        SoundFile sf = sfm.getSoundfile(addedFile.getID());
        assertTrue(sf!=null);
        System.out.println(sf.toString());

        sf = sfm.getSoundfileByName("E:\Eclipse_Prj\pSound\data\Adrenaline01.wav");
        assertTrue(sf!=null);
        System.out.println(sf.toString());
    } catch (RapsManagerException e) {
        fail(e.getMessage());
    }
}

@Test(expected=RapsManagerException.class)
public void testGetWithInvalidId() {
    SoundFileManager sfm = new SoundFileManager();

    sfm.getSoundfile(-100);
}

@Test(expected=RapsManagerException.class)
public void testGetWithInvalidName() {
    SoundFileManager sfm = new SoundFileManager();

    sfm.getSoundfileByName(new String());
}

回答by Donal Fellows

If you have an expected exception and you can't use an annotation to trap it, you need to catch it and assert that you've got what you expected. For example:

如果你有一个预期的异常并且你不能使用注解来捕获它,你需要捕获它并断言你得到了你所期望的。例如:

Throwable caught = null;
try {
   somethingThatThrows();
} catch (Throwable t) {
   caught = t;
}
assertNotNull(caught);
assertSame(FooException.class, caught.getClass());

If you can use an annotation instead, do that as it's much clearer. But that's not always possible (e.g., because you're testing a sequence of methods or because you're using JUnit 3).

如果您可以改用注释,请这样做,因为它更清晰。但这并不总是可能的(例如,因为您正在测试一系列方法或因为您正在使用 JUnit 3)。

回答by rwitzel

The most concise syntax is provided by catch-exception:

catch-exception提供了最简洁的语法:

public void testGet() {
    SoundFileManager sfm = new SoundFileManager();
    ... // setup sound file manager

    verifyException(sfm, RapsManagerException.class)
       .getSoundfile(-100);

    verifyException(sfm, RapsManagerException.class)
       .getSoundfileByName(new String());
}

回答by Jordan

In Java 8, you can use lambda expressions to get tighter control over when the exception is thrown. If you use the annotations method then you're only asserting that the exception is thrown somewhere in the test method. If you're executing more than one line of code in the test then you risk your test passing when it should fail. Java 8 solution is something like this.

在 Java 8 中,您可以使用 lambda 表达式来更严格地控​​制何时抛出异常。如果您使用 annotations 方法,那么您只是断言在测试方法中的某个地方抛出了异常。如果您在测试中执行了不止一行代码,那么您可能会在测试失败时冒着通过测试的风险。Java 8 解决方案是这样的。

static void <T extends Exception> expectException(Class<T> type, Runnable runnable) {
    try {
        runnable.run()
    } catch (Exception ex) {
        assertTrue(ex.getClass().equals(type));
        return;
    }
    assertTrue(false);
}

Usage:

用法:

@Test
public void test() 
    MyClass foo = new MyClass();
    // other setup code here ....
    expectException(MyException.class, () -> foo.bar());
}