编辑:目前不提供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的使用?
答案 0 :(得分:32)
我建议您需要将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());
}
}
答案 1 :(得分:12)
如果你有一个预期的异常并且你不能使用注释来捕获它,你需要捕获它并断言你已经得到了你所期望的。例如:
Throwable caught = null;
try {
somethingThatThrows();
} catch (Throwable t) {
caught = t;
}
assertNotNull(caught);
assertSame(FooException.class, caught.getClass());
如果您可以使用注释,请执行此操作,因为它更清晰。但这并不总是可行的(例如,因为您正在测试一系列方法,或者因为您正在使用JUnit 3)。
答案 2 :(得分:3)
使用JUnit 4,您可以改为使用注释。但是,您应该将测试分为3种不同的方法,以便干净地工作。请注意,在第一个场景中捕获异常的IMHO应该是失败的,因此我相应地修改了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());
}
答案 3 :(得分: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());
}
答案 4 :(得分:1)
在Java 8中,您可以使用lambda表达式来更严格地控制何时抛出异常。如果您使用注释方法,那么您只是断言在测试方法中的某处抛出了异常。如果您在测试中执行了多行代码,那么当测试失败时,您将面临测试通过的风险。 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());
}