JUnit 异常测试

发布于 2024-09-06 17:37:00 字数 1410 浏览 2 评论 0原文

编辑:目前 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 的使用?

Edit: Not JUnit 4 available at this time.

Hi there,

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鸵鸟症 2024-09-13 17:37:00

我建议您需要将 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());
}
}

I suggest that you need to break up testGet into 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.

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

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());
}
}
む无字情书 2024-09-13 17:37:00

如果您有预期的异常,并且无法使用注释来捕获它,则需要捕获它并断言您已经得到了预期的结果。例如:

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

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

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).

别忘他 2024-09-13 17:37:00

使用 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());
}

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 catch block accordingly.

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());
}
孤蝉 2024-09-13 17:37:00

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

The most concise syntax is provided by 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());
}
森罗 2024-09-13 17:37:00

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

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.

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());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文