【问题标题】:JUnit 4 Expected Exception typeJUnit 4 预期异常类型
【发布时间】:2013-05-23 20:54:51
【问题描述】:

我正在尝试对其他人编写的代码进行 JUnit 测试,但我不知道如何测试异常,因为异常似乎缺少类型。

public Pirate(String name, int initialGold) throws Exception {
    if(initialGold < 0)
        throw new Exception("Init Gold must be >= 0");
    this.name = name;
    this.numGold = initialGold;
    this.health = Pirate.DEFAULT_HEALTH;
    this.isCursed = false;
}

我的 JUnit 代码 sn-p:

@Test
public static void constructorTest() throws Exception{
    rodgers = new Pirate("Dread Pirate Rodgers", 10000);
    assertEquals("Dread Pirate Rodgers" , rodgers.getName());
    assertEquals(10000, rodgers.getNumGold());
    assertEquals(100, rodgers.getHealth());
    assertEquals(false, rodgers.getIsCursed());
}

@Test()
public static void exceptionTest() throws Exception{
    rodgers = new Pirate("Dread Pirate Rodgers" , -100);

}

我知道我需要在 test 的括号中加上 expected =(某种类型的异常),但我对异常类型一无所知。

【问题讨论】:

  • 运行测试看看会发生什么。
  • 您正在编写一个测试:您想验证是否引发了特定类型的异常。目前您实际上 正在抛出Exception,但这是一个糟糕的选择——它可能应该是IllegalArgumentException。无论哪种方式,您的测试基本上都需要检查是否抛出了正确的异常 - 但由您决定该类型是什么。
  • 为什么rodgers是一个类字段?
  • 被测代码抛出异常 - 这是您应该放入预期 = ..... 子句的类型。 (异常其实就是java.lang.Exception)
  • 我确定我会后悔的,但是海盗班应该为任何不名为“ROBERTS”的“恐惧”海盗提出一个“想要的”例外是的,是的 - 继续下去-修改我 :-) en.wikipedia.org/wiki/Dread_Pirate_Roberts

标签: java object testing junit


【解决方案1】:

在 JUnit 4.7 中实际上有一个替代 @Test(expected=Xyz.class) 的方法,使用 RuleExpectedException

在您的测试用例中,您声明一个带有@Rule 注释的ExpectedException,并为其分配一个默认值ExpectedException.none()。然后在您期望异常的测试中,将该值替换为实际的期望值。这样做的好处是无需使用丑陋的 try/catch 方法,您可以进一步指定异常中的消息是什么

@Rule public ExpectedException thrown= ExpectedException.none();

@Test
public void myTest() {
    thrown.expect( Exception.class );
    thrown.expectMessage("Init Gold must be >= 0");

    rodgers = new Pirate("Dread Pirate Rodgers" , -100);
}

使用此方法,您可能能够测试通用异常中的消息是否是特定的。

添加 使用ExpectedException 的另一个优点是您可以在测试用例的上下文中更精确地确定异常的范围。如果您仅在测试中使用@Test(expected=Xyz.class) 注释,则可以在测试代码中的任何位置抛出 Xyz 异常——包括测试方法中的任何测试设置或预断言。这可能会导致误报。

使用 ExpectedException,您可以将指定 thrown.expect(Xyz.class) 推迟到任何设置和预断言之后,就在实际调用被测方法之前。因此,您可以更准确地确定由实际方法调用引发的异常,而不是任何测试夹具本身。

JUnit 5 注意:

JUnit 5 JUnit Jupiter 完全删除了@Test(expected=...)@RuleExpectedException。它们被新的 assertThrows() 取代,这需要使用 Java 8 和 lambda 语法。 ExpectedException 仍可用于 JUnit 5 到 JUnit Vintage。此外,JUnit Jupiter 还将通过使用 junit-jupiter-migrationsupport module 继续支持 JUnit 4 ExpectedException,但前提是您添加了额外的 @EnableRuleMigrationSupport 类级别注释。

【讨论】:

  • +1,因为当您使用@Test(expected=IllegalArgumentException.class) 时,您并不确切知道测试中的哪一行会引发异常。因此,如果错误的行抛出异常,测试将通过,但您的代码可能存在潜在问题。
  • 同意,@Rule ExpectedException 的另一个巨大优势。
  • 别忘了 ExpectedException 必须声明为 public。
【解决方案2】:

您可以在 @Test 注释中使用 expected 提供明确的 catch 块并发出 fail如果程序流程不符合预期。

@Test(expected=Exception.class) // java.lang.Exception
public static void exceptionTest() throws Exception {
    rodgers = new Pirate("Dread Pirate Rodgers" , -100);
}

@Test
public static void exceptionTest() throws Exception {
    try {
        rodgers = new Pirate("Dread Pirate Rodgers" , -100);
        fail("should not reach this");
    } catch(Exception e) {
        // ok
    }
}

我个人的偏好是第一个解决方案。

【讨论】:

    【解决方案3】:

    您可以使用 JUnit 'expected' 来测试异常:

    @Test(expected = ExceptionYouWishToTestFor.class)  
    public void divisionWithException() {  
        // Test Code
    }
    

    之后,您可以在代码中抛出该特定异常。

    【讨论】:

      【解决方案4】:

      如果黄金不大于或等于零,我不会抛出Exception。我会抛出一个IllegalArgumentException。听起来你的Pirate 拥有负数的黄金当然是违法的。

      public Pirate(String name, int initialGold) {
          if(initialGold < 0)
              throw new IllegalArgumentException("Init Gold must be >= 0");
      

      然后在您的 JUnit 测试用例中,期待 IllegalArgumentException

      @Test(expected=IllegalArgumentException.class)
      public static void exceptionTest() {
      

      【讨论】:

      • 虽然我同意这是更好的实现方式,但我根本不应该更改海盗类。
      • 如果你不能改变 Pirate 构造函数抛出 Exception 的事实,那么你将不得不忍受@Test(expected=Exception.class)
      • 添加 .class 使其正常工作并正常测试,谢谢
      • 抛出Exception 不是一个好习惯。您应该使异常更有意义。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多