Java TestNG:如何测试强制异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3677271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TestNG: How to test for mandatory exceptions?
提问by Christopher Parker
I'd like to write a TestNG test to make sure an exception is thrown under a specific condition, and fail the test if the exception is not thrown. Is there an easy way to do this without having to create an extra boolean variable?
我想编写一个 TestNG 测试来确保在特定条件下抛出异常,如果没有抛出异常,则测试失败。有没有一种简单的方法可以做到这一点而不必创建额外的布尔变量?
A related blog post on this subject: http://konigsberg.blogspot.com/2007/11/testng-and-expectedexceptions-ive.html
关于此主题的相关博客文章:http: //konigsberg.blogspot.com/2007/11/testng-and-expectedexceptions-ive.html
采纳答案by Cedric Beust
@Test(expectedExceptions)
is useful for the most common cases:
@Test(expectedExceptions)
对于最常见的情况很有用:
- You expect a specific exception to be thrown
- You need the message of that exception to contain specific words
- 你期望抛出一个特定的异常
- 您需要该异常的消息来包含特定的词
Per the documentation a test will fail if no expectedException
is thrown:
根据文档,如果expectedException
抛出no ,则测试将失败:
The list of exceptions that a test method is expected to throw. If no exception or a different than one on this list is thrown, this test will be marked a failure.
测试方法预期抛出的异常列表。如果没有抛出异常或与此列表中的异常不同,则此测试将被标记为失败。
Here are a few scenarios where @Test(expectedExceptions)
is not sufficient:
以下是一些@Test(expectedExceptions)
不够充分的场景:
- Your test method has several statements and only one of them is expected to throw
- You are throwing your own type of exception and you need to make sure it matches a certain criterion
- 您的测试方法有几个语句,预计只有其中一个会抛出
- 您正在抛出自己类型的异常,并且需要确保它符合某个标准
In such cases, you should just revert to the traditional (pre-TestNG) pattern:
在这种情况下,您应该恢复到传统的(测试前的)模式:
try {
// your statement expected to throw
fail();
}
catch(<the expected exception>) {
// pass
}
回答by Thomas L?tzer
Why don't you use the try/fail/catch pattern mentioned in the blog post you linked to?
为什么不使用链接到的博客文章中提到的 try/fail/catch 模式?
回答by Vineet Reynolds
I have to disagree with the the article on the nature of the testing techniques employed. The solution employs a gate, to verify if the test should succeed or fail in an intermediate stage.
我不得不不同意关于所采用的测试技术的性质的文章。该解决方案使用一个门来验证测试在中间阶段是成功还是失败。
In my opinion, it is better to employ Guard Assertions, especially for such tests (assuming that the test does not turn out to be long-winded and complex, which is an anti-pattern in itself). Using guard-assertions forces you to design the SUT in either of the following ways:
在我看来,最好使用Guard Assertions,尤其是对于此类测试(假设测试不会变得冗长和复杂,这本身就是一种反模式)。使用保护断言强制您以下列任一方式设计 SUT:
- design the method itself to provide enough information in the result on whether the invocation passed or succeeded. Sometimes, this cannot be done as the intention of the designer is to not return a result, and instead throw an exception (this can be handled in the second case).
- design the SUT so that it's state can be verifiedafter each significant method invocation.
- 设计方法本身以在结果中提供足够的信息,说明调用是通过还是成功。有时,这无法完成,因为设计者的意图是不返回结果,而是抛出异常(这可以在第二种情况下处理)。
- 设计 SUT,以便在每次重要的方法调用后都可以验证它的状态。
But before we consider the above possibilities, have a look at the following snippet again:
但在我们考虑上述可能性之前,请再次查看以下代码片段:
plane.bookAllSeats();
plane.bookPlane(createValidItinerary(), null);
If the intention is to test bookPlane() and verify for execution of that method, it is better to have bookAllSeats() in a fixture. In my understanding, invoking bookAllSeats() is equivalent to setting up the SUT to ensure that the invocation of bookPlane() fails, and hence having a fixture to do the same would make for a more readable test. If the intention are different, I would recommend testing the state after every transition (as I normally would do in functional tests), to help pinpoint the original cause of failure.
如果目的是测试 bookPlane() 并验证该方法的执行,最好在夹具中使用 bookAllSeats()。在我的理解中,调用 bookAllSeats() 相当于设置 SUT 以确保 bookPlane() 的调用失败,因此有一个夹具来执行相同的操作将使测试更具可读性。如果意图不同,我建议在每次转换后测试状态(就像我通常在功能测试中所做的那样),以帮助查明失败的原始原因。
回答by rwitzel
catch-exceptionprovides probably everything you need to test for expected exceptions.
catch-exception可能提供了测试预期异常所需的一切。
回答by harunurhan
Use @Test
annotation to check expected exceptions.
使用@Test
注解来检查预期的异常。
@Test(
expectedExceptions = AnyClassThatExtendsException.class,
expectedExceptionsMessageRegExp = "Exception message regexp"
)
Or if you don't want to check for exception message, only below is enough
或者,如果您不想检查异常消息,则仅在下面就足够了
@Test(expectedExceptions = AnyClassThatExtendsException.class)
In that way, you don't need to use ugly try catch block, just invoke you exception-thrower method inside the test.
这样,您就不需要使用丑陋的 try catch 块,只需在测试中调用异常抛出方法即可。
回答by Buddhima Udaranga
if you are using java 7 and testng this can be used for java 8 you can also use lambda expressions
如果您使用的是 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());
回答by Java Impatient
I created a custom Stack data structure which is backed by an array. The push() method throws a custom exception when the stack is full and you still try to push() data into the stack. You could handle it like this:
我创建了一个由数组支持的自定义 Stack 数据结构。当堆栈已满并且您仍然尝试将 push() 数据放入堆栈时,push() 方法会抛出自定义异常。你可以处理它像这样:
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.
}
Alternately, you could change your api as suggested 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." );
}
I updated the push method to return true or false if the operation passed or failed, instead of returning void. The Java Stack.push(item) returns the element you tried to insert instead of void. I don't know why. But, it also inherits a similar method addElement(item) from Vector which returns void.
如果操作通过或失败,我更新了 push 方法以返回 true 或 false,而不是返回 void。在Java堆栈.push(项目)返回你试图插入,而不是无效的元素。我不知道为什么。但是,它还从 Vector 继承了一个类似的 addElement(item) 方法,该方法返回 void。
One minor downside I see to making push(item) return a boolean or void is that you are stuck with those return types. If you return Stack instead then you can write code conveniently like this stack.push(1).push(2).push(3).pop()
. But, I don't know how often one would have to write code like that.
我认为让 push(item) 返回布尔值或空值的一个小缺点是你被这些返回类型卡住了。如果您改为返回 Stack,那么您可以像这样方便地编写代码stack.push(1).push(2).push(3).pop()
。但是,我不知道人们需要多久编写一次这样的代码。
Similarly, my pop() method used to return a generic type "T" and used to throw an exception if the stack was empty. I updated it to return Optional<T>
instead.
类似地,我的 pop() 方法过去常常返回一个泛型类型“T”,并在堆栈为空时抛出异常。我更新了它以返回Optional<T>
。
@Test
public void popEmptyStack(){
Assert.assertTrue(stack.pop().isEmpty());
}
I guess I am now free of the clunky try-catch blocks and TestNg expectedExceptions. Hopefully, my design is good now.
我想我现在摆脱了笨重的 try-catch 块和 TestNg expectedExceptions。希望我的设计现在很好。