TestNG:如何测试强制例外?

时间:2010-09-09 14:00:01

标签: java unit-testing testng

我想编写一个TestNG测试来确保在特定条件下抛出异常,如果没有抛出异常则测试失败。有没有必要创建额外的布尔变量的简单方法呢?

有关此主题的相关博文:http://konigsberg.blogspot.com/2007/11/testng-and-expectedexceptions-ive.html

7 个答案:

答案 0 :(得分:25)

@Test(expectedExceptions)对最常见的情况很有用:

  • 您希望抛出特定的异常
  • 您需要该例外的消息才能包含特定字词

根据文档,如果没有抛出expectedException,测试将失败:

  

预期测试方法抛出的异常列表。如果抛出此列表中没有异常或不同的异常,则此测试将标记为失败。

以下是@Test(expectedExceptions)不足的几种情况:

  • 您的测试方法有多个语句,只有一个语句可以抛出
  • 您正在抛出自己的异常类型,并且需要确保它符合某个标准

在这种情况下,您应该恢复到传统的(pre-TestNG)模式:

try {
  // your statement expected to throw
  fail();
}
catch(<the expected exception>) {
  // pass
}

答案 1 :(得分:10)

使用simple注释来检查预期的例外情况。

@Test

或者,如果您不想检查异常消息,只有下面的内容足够

@Test(
    expectedExceptions = AnyClassThatExtendsException.class,
    expectedExceptionsMessageRegExp = "Exception message regexp"
)

通过这种方式,您不需要使用丑陋的try catch块,只需在测试中调用exception-thrower方法。

答案 2 :(得分:1)

我不同意有关所用测试技术性质的文章。该解决方案使用一个门,以验证测试是否应该在中间阶段成功或失败。

在我看来,最好使用Guard Assertions,特别是对于这样的测试(假设测试结果并不是冗长而复杂的,这本身就是一种反模式)。使用guard-assertions迫使您通过以下任一方式设计SUT:

  • 设计方法本身,在结果中提供关于调用是通过还是成功的足够信息。有时,这是不可能的,因为设计者的意图是不返回结果,而是抛出异常(这可以在第二种情况下处理)。
  • 设计SUT,使其在每次重要的方法调用后都为state can be verified

但在我们考虑上述可能性之前,请再次查看以下代码段:

plane.bookAllSeats();
plane.bookPlane(createValidItinerary(), null);

如果打算测试bookPlane()并验证该方法的执行,最好在fixture中使用bookAllSeats()。在我的理解中,调用bookAllSeats()相当于设置SUT以确保bookPlane()的调用失败,因此有一个夹具来做同样的事情会使更可读的测试。如果意图不同,我建议在每次转换后测试状态(正如我通常在功能测试中所做的那样),以帮助查明失败的原始原因。

答案 3 :(得分:0)

为什么不使用链接到的博客文章中提到的try / fail / catch模式?

答案 4 :(得分:0)

catch-exception可能提供测试预期异常所需的一切。

答案 5 :(得分:0)

如果您使用的是Java 7和testng,则可以将其用于Java 8,也可以使用lambda表达式

class A implements ThrowingRunnable{


            @Override
            public void run() throws AuthenticationFailedException{
                spy.processAuthenticationResponse(mockRequest, mockResponse, authenticationContext);
            }
        }
        assertThrows(AuthenticationFailedException.class,new A());

答案 6 :(得分:0)

我创建了一个自定义的Stack数据结构,该结构由数组支持。当堆栈已满并且您仍然尝试将数据推入堆栈时,push()方法将引发自定义异常。您可以like this来处理它:

public class TestStackDataStructure {
    //All test methods use this variable.
    public Stack<String> stack;//This Stack class is NOT from Java.

    @BeforeMethod
    public void beforeMethod(){
    //Don't want to repeat this code inside each test, especially if we have several lines for setup.
        stack = new Stack<>(5);
    }

    @Test
    public void pushItemIntoAFullStack(){
        //I know this code won't throw exceptions, but what if we have some code that does ?
        IntStream.rangeClosed(1,5).mapToObj(i -> i + "").forEach(stack::push);

        try{
            stack.push("6");
            Assert.fail("Exception expected.");
        }catch (StackIsFullException ex) {
            // do nothing;
        }
    }

    //Other tests here.
}

或者,您也可以按照建议的here更改api:

@Test
public void pushItemIntoAFullStack(){
    IntStream.rangeClosed(1,5).mapToObj(i -> i + "").forEach(stack::push);
    Assert.assertFalse( stack.push("6"), "Expected push to fail." );
}

我更新了push方法,如果操作通过或失败,则返回true或false,而不是返回void。 Java Stack。push(item)返回您尝试插入的元素,而不是void。我不知道为什么但是,它也从Vector继承了类似的方法addElement(item),该方法返回void。

我看到使push(item)返回布尔值或void的一个小缺点是您被这些返回类型所困扰。如果返回堆栈,则可以像这样stack.push(1).push(2).push(3).pop()那样方便地编写代码。但是,我不知道人们需要多久编写一次这样的代码。

类似地,我的pop()方法用于返回通用类型“ T”,并在堆栈为空时用于引发异常。我将其更新为返回Optional<T>

@Test
public void popEmptyStack(){
    Assert.assertTrue(stack.pop().isEmpty());
}

我想我现在摆脱了笨拙的try-catch块和TestNg ExpectedExceptions。希望我的设计现在很好。