15

编辑:此时没有可用的 JUnit 4。

你好呀,

我有一个关于使用 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());
        }

    }

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

4

5 回答 5

33

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

一旦你有了它,你就可以使用 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());
}
}
于 2010-06-21T08:54:46.433 回答
13

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

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

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

于 2010-06-21T08:52:42.603 回答
3

使用 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());
}
于 2010-06-21T08:48:14.370 回答
2

最简洁的语法由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());
}
于 2012-06-22T16:52:14.943 回答
1

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

用法:

@Test
public void test() 
    MyClass foo = new MyClass();
    // other setup code here ....
    expectException(MyException.class, () -> foo.bar());
}
于 2017-07-07T02:36:39.467 回答