JUnit异常测试
编辑:目前不提供JUnit 4。JUnit异常测试
那里嗨,
我有一个关于使用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的使用?
我建议你需要将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());
}
}
我喜欢这个,但我害怕在运行的项目中切换到JUnit4。 – InsertNickHere 2010-06-21 09:01:13
@InsertNickHere:您的谨慎是值得赞扬的,但我建议在这种情况下错位。 JUnit4可以在不改变的情况下运行JUnit3风格的测试,从而允许您逐次迁移一个测试。另外,JUnit4现在已经4岁了,真的是你感动了。 – skaffman 2010-06-21 09:29:46
我必须完全同意你 - 在这种情况下,我必须将其移至JUnit 4. – InsertNickHere 2010-06-21 09:35:55
使用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());
}
正如我上面所说的,我喜欢这个主意,但我不愿意在正在运行的项目中切换到JUnit4。 – InsertNickHere 2010-06-21 09:02:04
@InsertNickHere,无论如何,你应该把你的测试分解成3个独立的方法,通常的设置。那么如果你真的想最小化异常处理代码(并且你有很多重复的代码就像你展示的那样),你可以将try/catch提取到一个单独的方法中,并通过一个接口传递实际的方法进行测试(但这真是矫枉过正恕我直言,它使你的测试代码更难理解)。 – 2010-06-21 09:08:06
如果你有一个预期的异常,你不能使用注释来捕获它,你需要抓住它,并断言,你已经得到了你所期望的。例如:
Throwable caught = null;
try {
somethingThatThrows();
} catch (Throwable t) {
caught = t;
}
assertNotNull(caught);
assertSame(FooException.class, caught.getClass());
如果您可以使用一个注释来代替它,那么它会更清晰。但是这并不总是可行的(例如,因为您正在测试一系列方法或者因为您在使用JUnit 3)。
对不起,但我没有看到你的版本相比我的任何优势。也许没有JUnit3 :( – InsertNickHere 2010-06-21 09:03:45
)你在测试用例中放置太多,你在'try'中放置太多了,你正在打印消息来手动读取,而不是让测试断言失败!(您的代码中嵌入了非便携式路径,但这是您的业务......) – 2010-06-21 09:15:18
路径仅用于此示例,我不会在此处发布100%的原始代码。不过谢谢你的建议。 :) – InsertNickHere 2010-06-21 09:35:03
最简洁的语法是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());
}
在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());
}
我会建议反对这样做的System.out.println内部测试。 System.out和System.err倾向于混淆并产生乱码测试输出。 – RockyMM 2012-11-20 12:31:59