I know that one way to do it would be:
我知道一种方法是:
@Test
public void foo(){
try{
//execute code that you expect not to throw Exceptions.
}
catch(Exception e){
fail("Should not have thrown any exception");
}
}
Is there any cleaner way of doing this. (Probably using Junit's @Rule
?)
有没有更干净的方法。(可能使用Junit的@Rule ?)
11 个解决方案
#1
128
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
你走错路了。测试您的功能:如果一个异常被抛出,测试将自动失败。如果没有抛出异常,您的测试将全部显示为绿色。
I have noticed this question garners interest from time to time so I'll expand a little.
我注意到这个问题不时引起人们的兴趣,所以我要扩展一下。
Background to unit testing
When you're unit testing it's important to define to yourself what you consider a unit of work. Basically: an extraction of your codebase that may or may not include multiple methods or classes that represents a single piece of functionality.
当你在进行单元测试时,重要的是给自己定义一个工作单元。基本上:代码基的提取,可能包含也可能不包含表示单个功能片段的多个方法或类。
Or, as defined in The art of Unit Testing, 2nd Edition by Roy Osherove, page 11:
或者,正如定义在单元测试的艺术,由罗伊Osherove第二版,页11:
A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's trustworthy, readable, and maintainable. It's consistent in its results as long as production code hasn't changed.
单元测试是一段自动的代码,它调用被测试的工作单元,然后检查有关该单元的单个最终结果的一些假设。单元测试几乎总是使用单元测试框架编写的。它很容易编写,运行速度很快。它是可信的、可读的、可维护的。只要产品代码没有改变,它的结果就会是一致的。
What is important to realize is that one unit of work usually isn't just one method but at the very basic level it is one method and after that it is encapsulated by other unit of works.
重要的是要意识到,一个单位的工作通常不只是一种方法,而是在最基本的层面上,它是一种方法,然后它被其他单位的作品封装起来。
Ideally you should have a test method for each separate unit of work so you can always immediately view where things are going wrong. In this example there is a basic method called getUserById()
which will return a user and there is a total of 3 unit of works.
理想情况下,您应该为每个单独的工作单元都有一个测试方法,这样您就可以随时查看哪里出了问题。在这个示例中,有一个名为getUserById()的基本方法,它将返回一个用户,总共有3个工作单元。
The first unit of work should test whether or not a valid user is being returned in the case of valid and invalid input.
Any exceptions that are being thrown by the datasource have to be handled here: if no user is present there should be a test that demonstrates that an exception is thrown when the user can't be found. A sample of this could be the IllegalArgumentException
which is caught with the @Test(expected = IllegalArgumentException.class)
annotation.
第一个工作单元应该测试在有效和无效输入的情况下是否返回有效用户。任何由数据源抛出的异常都必须在这里进行处理:如果没有用户存在,那么应该有一个测试来说明在找不到用户时抛出了异常。其中的一个示例可能是被@Test捕获的IllegalArgumentException(期望= IllegalArgumentException.class)注释。
Once you have handled all your usecases for this basic unit of work, you move up a level. Here you do exactly the same, but you only handle the exceptions that come from the level right below the current one. This keeps your testing code well structured and allows you to quickly run through the architecture to find where things go wrong, instead of having to hop all over the place.
一旦你处理你所有的用例这个基本工作单元,你向上移动一个水平。你做一模一样的,但是你只处理异常来自对低于当前水平。这使你的测试代码结构化和允许您快速浏览架构找到出错的地方,不用跳的到处都是。
Handling a tests' valid and faulty input
At this point it should be clear how we're going to handle these exceptions. There are 2 types of input: valid input and faulty input (the input is valid in the strict sense, but it's not correct).
此时,我们应该清楚地知道如何处理这些异常。输入有两种类型:有效输入和错误输入(输入在严格意义上是有效的,但不正确)。
When you work with valid input you're setting the implicit expectancy that whatever test you write, will work.
当您使用有效的输入时,您正在设置隐式期望,即无论您编写什么测试,都将工作。
Such a method call can look like this: existingUserById_ShouldReturn_UserObject
. If this method fails (e.g.: an exception is thrown) then you know something went wrong and you can start digging.
这样的方法调用可以如下所示:existingUserById_ShouldReturn_UserObject。如果这个方法失败了(例如:抛出一个异常),那么您就知道出了问题,您可以开始挖掘了。
By adding another test (nonExistingUserById_ShouldThrow_IllegalArgumentException
) that uses the faulty input and expects an exception you can see whether your method does what it is supposed to do with wrong input.
通过添加另一个测试(不存在的userbyid_shouldthrow _illegalargumentexception),该测试使用错误的输入并期望出现异常,您可以看到您的方法是否使用错误的输入执行它应该执行的操作。
TL;DR
You were trying to do two things in your test: check for valid and faulty input. By splitting this into two method that each do one thing, you will have much clearer tests and a much better overview of where things go wrong.
在测试中,您试图做两件事:检查有效输入和错误输入。通过将它分成两种方法,每个方法只做一件事,您将会有更清晰的测试和更好的概述。
By keeping the layered unit of works in mind you can also reduce the amount of tests you need for a layer that is higher in the hierarchy because you don't have to account for every thing that might have gone wrong in the lower layers: the layers below the current one are a virtual guarantee that your dependencies work and if something goes wrong, it's in your current layer (assuming the lower layers don't throw any errors themselves).
,必须牢记的分层单位工作还可以减少测试需要一层更高的层次结构,因为你不必每件事可能占了较低的层:下层当前是一个虚拟的保证你的依赖关系工作,如果出现错误,这是在当前层较低的层(假设不抛出任何错误自己)。
#2
28
I stumbled upon this because of SonarQubes rule "squid:S2699": "Add at least one assertion to this test case."
我偶然发现了这一点,因为SonarQubes规则“squid:S2699”:“在这个测试用例中添加至少一个断言。”
I had a simple test those only goal it was, that it went through without exception.
我做了一个简单的测试,这是唯一的目标,它毫无例外地通过了。
Imagine this simple code:
想象一下这个简单的代码:
public class Printer {
public static void printLine(final String line) {
System.out.println(line);
}
}
What kind of assertion can be added to test this method? Sure, you can make a try catch around it, but that is only code bloat.
可以添加什么样的断言来测试这个方法?当然,您可以尝试捕获它,但这只是代码膨胀。
The solution gives you JUnit itself.
解决方案提供了JUnit本身。
In cases no exception is thrown and you want to explicitly illustrate this behaviour simply add the expected like the following:
在没有抛出异常的情况下,您想要显式地说明这种行为,只需添加如下所示的期望:
@Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
Printer.printLine("line");
}
Test.None.class is the default for the expected value.
Test.None。类是期望值的默认值。
#3
25
Java 8 makes this a lot easier, and Kotlin/Scala doubly so.
Java 8使这变得容易得多,而Kotlin/Scala更是如此。
We can write a little utility class
我们可以写一个实用类
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
and then your code becomes simply:
然后你的代码变得简单:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
If you dont have access to Java-8, I would use a painfully old java facility: aribitrary code blocks and a simple comment
如果你不访问java 8,我将使用一个非常老的java工具:aribitrary代码块和一个简单的评论
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
And finally, with kotlin, a language I've recently fallen in love with:
最后,芬兰湾的科特林,一种语言我最近爱上了:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
Though there is a lot of room to fiddle with exactly how you want to express this, I was always a fan of fluent assertions.
尽管有很大的空间去弄清楚你想要如何表达这个观点,但我一直很喜欢流利的断言。
Regarding
关于
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
你走错路了。测试您的功能:如果一个异常被抛出,测试将自动失败。如果没有抛出异常,您的测试将全部显示为绿色。
This is correct in principle but incorrect in conclusion.
这在原则上是对的,但是结论是错误的。
Java allows exceptions for flow of control. This is done by the JRE runtime itself in APIs like Double.parseDouble
via a NumberFormatException
and Paths.get
via a InvalidPathException
.
Java允许控制流的异常。这是由JRE运行时本身在诸如Double之类的api中完成的。通过NumberFormatException和路径进行解析。通过InvalidPathException得到。
Given you've written a component that validates Number strings for Double.ParseDouble
, maybe using a Regex, maybe a hand-written parser, or perhaps something that embeds some other domain rules that restricts the range of a double to something specific, how best to test this component? I think an obvious test would be to assert that, when the resulting string is parsed, no exception is thrown. I would write that test using either the above assertDoesNotThrow
or /*comment*/{code}
block. Something like
给你写一个组件来验证字符串数量翻倍。使用Regex ParseDouble,也许,也许一个手写的解析器,或者一些嵌入其他域规则限制对某些具体的双重的范围,如何测试这个组件?我认为一个明显的测试是断言,当生成的字符串解析,没有异常。我会写测试使用上述assertDoesNotThrow或/ *注释* / } {代码块。类似的
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
I would also encourage you to parameterize this test on input
using Theories
or Parameterized
so that you can more easily re-use this test for other inputs. Alternatively, if you want to go exotic, you could go for a test-generation tool (and this). TestNG has better support for parameterized tests.
我也鼓励你这个测试的参数输入使用理论或参数化,这样你可以更容易地重用这个测试对其他输入。另外,如果你想去异国情调的,你可以去测试生成工具(这)。TestNG具有更好的支持参数化测试。
What I find particularly disagreeable is the recommendation of using @Test(expectedException=IllegalArgumentException.class)
, this exception is dangerously broad. If your code changes such that the component under test's constructor has if(constructorArgument <= 0) throw IllegalArgumentException()
, and your test was supplying 0 for that argument because it was convenient --and this is very common, because good generating test data is a surprisingly hard problem--, then your test will be green-bar even though it tests nothing. Such a test is worse than useless.
我发现特别令人不快的是使用@Test(expectedException=IllegalArgumentException.class)的推荐,这个异常非常广泛。如果你的代码更改,这样被测试的组件的构造函数如果(constructorArgument < = 0)扔IllegalArgumentException(),和你的测试是为这一观点提供0,因为它是方便的,这是很常见的,因为好的生成测试数据是一个非常困难的问题,那么您的测试将绿条,尽管它没有测试。这样的测试比没用的还要糟糕。
#4
16
If you are unlucky enough to catch all errors in your code. You can stupidly do
如果您不幸捕获了代码中的所有错误。你愚蠢的可以做
class DumpTest {
Exception ex;
@Test
public void testWhatEver() {
try {
thisShouldThroughError();
} catch (Exception e) {
ex = e;
}
assertEquals(null,ex);
}
}
#5
9
With AssertJ fluent assertions 3.7.0:
使用AssertJ fluent断言3.7.0:
Assertions.assertThatCode(() -> toTest.method())
.doesNotThrowAnyException();
#6
2
Use assertNull(...)
使用assertNull(…)
@Test
public void foo() {
try {
//execute code that you expect not to throw Exceptions.
} catch (Exception e){
assertNull(e);
}
}
#7
#8
1
If you want to test that whether your test target consumes the exception. Just leave the test as (mock collaborator using jMock2):
如果您想测试您的测试目标是否使用了异常。让测试保持为(使用jMock2的模拟合作者):
@Test
public void consumesAndLogsExceptions() throws Exception {
context.checking(new Expectations() {
{
oneOf(collaborator).doSth();
will(throwException(new NullPointerException()));
}
});
target.doSth();
}
The test would pass if your target does consume the exception thrown, otherwise the test would fail.
如果您的目标确实使用抛出的异常,则测试将通过,否则测试将失败。
If you want to test your exception consumption logic, things get more complex. I suggest delegating the consumption to a collaborator which could be mocked. Therefore the test could be:
如果您想测试异常消耗逻辑,事情就会变得更加复杂。我建议把消费委托给一个可以被嘲笑的合作者。因此,测试可以是:
@Test
public void consumesAndLogsExceptions() throws Exception {
Exception e = new NullPointerException();
context.checking(new Expectations() {
{
allowing(collaborator).doSth();
will(throwException(e));
oneOf(consumer).consume(e);
}
});
target.doSth();
}
But sometimes it's over-designed if you just want to log it. In this case, this article(http://java.dzone.com/articles/monitoring-declarative-transac, http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/) may help if you insist tdd in this case.
但有时是过度设计的,如果你只是想需要进行日志记录。在这种情况下,这篇文章(http://java.dzone.com/articles/monitoring-declarative-transac,http://java.dzone.com/articles/monitoring-declarative-transac)可以帮助在这种情况下如果你坚持tdd。
#9
1
JUnit5 adds the assertAll() method for this exact purpose.
JUnit5为此目的添加了assertAll()方法。
assertAll( () -> foo() )
来源:JUnit 5 API
#10
0
The following fails the test for all exceptions, checked or unchecked:
以下是检查或不检查的所有异常的测试失败:
@Test
public void testMyCode() {
try {
runMyTestCode();
} catch (Throwable t) {
throw new Error("fail!");
}
}
#11
0
You can expect that exception is not thrown by creating a rule.
你可以认为不是通过创建一个规则抛出异常。
@Rule
public ExpectedException expectedException = ExpectedException.none();
#1
128
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
你走错路了。测试您的功能:如果一个异常被抛出,测试将自动失败。如果没有抛出异常,您的测试将全部显示为绿色。
I have noticed this question garners interest from time to time so I'll expand a little.
我注意到这个问题不时引起人们的兴趣,所以我要扩展一下。
Background to unit testing
When you're unit testing it's important to define to yourself what you consider a unit of work. Basically: an extraction of your codebase that may or may not include multiple methods or classes that represents a single piece of functionality.
当你在进行单元测试时,重要的是给自己定义一个工作单元。基本上:代码基的提取,可能包含也可能不包含表示单个功能片段的多个方法或类。
Or, as defined in The art of Unit Testing, 2nd Edition by Roy Osherove, page 11:
或者,正如定义在单元测试的艺术,由罗伊Osherove第二版,页11:
A unit test is an automated piece of code that invokes the unit of work being tested, and then checks some assumptions about a single end result of that unit. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's trustworthy, readable, and maintainable. It's consistent in its results as long as production code hasn't changed.
单元测试是一段自动的代码,它调用被测试的工作单元,然后检查有关该单元的单个最终结果的一些假设。单元测试几乎总是使用单元测试框架编写的。它很容易编写,运行速度很快。它是可信的、可读的、可维护的。只要产品代码没有改变,它的结果就会是一致的。
What is important to realize is that one unit of work usually isn't just one method but at the very basic level it is one method and after that it is encapsulated by other unit of works.
重要的是要意识到,一个单位的工作通常不只是一种方法,而是在最基本的层面上,它是一种方法,然后它被其他单位的作品封装起来。
Ideally you should have a test method for each separate unit of work so you can always immediately view where things are going wrong. In this example there is a basic method called getUserById()
which will return a user and there is a total of 3 unit of works.
理想情况下,您应该为每个单独的工作单元都有一个测试方法,这样您就可以随时查看哪里出了问题。在这个示例中,有一个名为getUserById()的基本方法,它将返回一个用户,总共有3个工作单元。
The first unit of work should test whether or not a valid user is being returned in the case of valid and invalid input.
Any exceptions that are being thrown by the datasource have to be handled here: if no user is present there should be a test that demonstrates that an exception is thrown when the user can't be found. A sample of this could be the IllegalArgumentException
which is caught with the @Test(expected = IllegalArgumentException.class)
annotation.
第一个工作单元应该测试在有效和无效输入的情况下是否返回有效用户。任何由数据源抛出的异常都必须在这里进行处理:如果没有用户存在,那么应该有一个测试来说明在找不到用户时抛出了异常。其中的一个示例可能是被@Test捕获的IllegalArgumentException(期望= IllegalArgumentException.class)注释。
Once you have handled all your usecases for this basic unit of work, you move up a level. Here you do exactly the same, but you only handle the exceptions that come from the level right below the current one. This keeps your testing code well structured and allows you to quickly run through the architecture to find where things go wrong, instead of having to hop all over the place.
一旦你处理你所有的用例这个基本工作单元,你向上移动一个水平。你做一模一样的,但是你只处理异常来自对低于当前水平。这使你的测试代码结构化和允许您快速浏览架构找到出错的地方,不用跳的到处都是。
Handling a tests' valid and faulty input
At this point it should be clear how we're going to handle these exceptions. There are 2 types of input: valid input and faulty input (the input is valid in the strict sense, but it's not correct).
此时,我们应该清楚地知道如何处理这些异常。输入有两种类型:有效输入和错误输入(输入在严格意义上是有效的,但不正确)。
When you work with valid input you're setting the implicit expectancy that whatever test you write, will work.
当您使用有效的输入时,您正在设置隐式期望,即无论您编写什么测试,都将工作。
Such a method call can look like this: existingUserById_ShouldReturn_UserObject
. If this method fails (e.g.: an exception is thrown) then you know something went wrong and you can start digging.
这样的方法调用可以如下所示:existingUserById_ShouldReturn_UserObject。如果这个方法失败了(例如:抛出一个异常),那么您就知道出了问题,您可以开始挖掘了。
By adding another test (nonExistingUserById_ShouldThrow_IllegalArgumentException
) that uses the faulty input and expects an exception you can see whether your method does what it is supposed to do with wrong input.
通过添加另一个测试(不存在的userbyid_shouldthrow _illegalargumentexception),该测试使用错误的输入并期望出现异常,您可以看到您的方法是否使用错误的输入执行它应该执行的操作。
TL;DR
You were trying to do two things in your test: check for valid and faulty input. By splitting this into two method that each do one thing, you will have much clearer tests and a much better overview of where things go wrong.
在测试中,您试图做两件事:检查有效输入和错误输入。通过将它分成两种方法,每个方法只做一件事,您将会有更清晰的测试和更好的概述。
By keeping the layered unit of works in mind you can also reduce the amount of tests you need for a layer that is higher in the hierarchy because you don't have to account for every thing that might have gone wrong in the lower layers: the layers below the current one are a virtual guarantee that your dependencies work and if something goes wrong, it's in your current layer (assuming the lower layers don't throw any errors themselves).
,必须牢记的分层单位工作还可以减少测试需要一层更高的层次结构,因为你不必每件事可能占了较低的层:下层当前是一个虚拟的保证你的依赖关系工作,如果出现错误,这是在当前层较低的层(假设不抛出任何错误自己)。
#2
28
I stumbled upon this because of SonarQubes rule "squid:S2699": "Add at least one assertion to this test case."
我偶然发现了这一点,因为SonarQubes规则“squid:S2699”:“在这个测试用例中添加至少一个断言。”
I had a simple test those only goal it was, that it went through without exception.
我做了一个简单的测试,这是唯一的目标,它毫无例外地通过了。
Imagine this simple code:
想象一下这个简单的代码:
public class Printer {
public static void printLine(final String line) {
System.out.println(line);
}
}
What kind of assertion can be added to test this method? Sure, you can make a try catch around it, but that is only code bloat.
可以添加什么样的断言来测试这个方法?当然,您可以尝试捕获它,但这只是代码膨胀。
The solution gives you JUnit itself.
解决方案提供了JUnit本身。
In cases no exception is thrown and you want to explicitly illustrate this behaviour simply add the expected like the following:
在没有抛出异常的情况下,您想要显式地说明这种行为,只需添加如下所示的期望:
@Test(expected = Test.None.class /* no exception expected */)
public void test_printLine() {
Printer.printLine("line");
}
Test.None.class is the default for the expected value.
Test.None。类是期望值的默认值。
#3
25
Java 8 makes this a lot easier, and Kotlin/Scala doubly so.
Java 8使这变得容易得多,而Kotlin/Scala更是如此。
We can write a little utility class
我们可以写一个实用类
class MyAssertions{
public static void assertDoesNotThrow(FailingRunnable action){
try{
action.run()
}
catch(Exception ex){
throw new Error("expected action not to throw, but it did!", ex)
}
}
}
@FunctionalInterface interface FailingRunnable { void run() throws Exception }
and then your code becomes simply:
然后你的代码变得简单:
@Test
public void foo(){
MyAssertions.assertDoesNotThrow(() -> {
//execute code that you expect not to throw Exceptions.
}
}
If you dont have access to Java-8, I would use a painfully old java facility: aribitrary code blocks and a simple comment
如果你不访问java 8,我将使用一个非常老的java工具:aribitrary代码块和一个简单的评论
//setup
Component component = new Component();
//act
configure(component);
//assert
/*assert does not throw*/{
component.doSomething();
}
And finally, with kotlin, a language I've recently fallen in love with:
最后,芬兰湾的科特林,一种语言我最近爱上了:
fun (() -> Any?).shouldNotThrow()
= try { invoke() } catch (ex : Exception){ throw Error("expected not to throw!", ex) }
@Test fun `when foo happens should not throw`(){
//...
{ /*code that shouldn't throw*/ }.shouldNotThrow()
}
Though there is a lot of room to fiddle with exactly how you want to express this, I was always a fan of fluent assertions.
尽管有很大的空间去弄清楚你想要如何表达这个观点,但我一直很喜欢流利的断言。
Regarding
关于
You're approaching this the wrong way. Just test your functionality: if an exception is thrown the test will automatically fail. If no exception is thrown, your tests will all turn up green.
你走错路了。测试您的功能:如果一个异常被抛出,测试将自动失败。如果没有抛出异常,您的测试将全部显示为绿色。
This is correct in principle but incorrect in conclusion.
这在原则上是对的,但是结论是错误的。
Java allows exceptions for flow of control. This is done by the JRE runtime itself in APIs like Double.parseDouble
via a NumberFormatException
and Paths.get
via a InvalidPathException
.
Java允许控制流的异常。这是由JRE运行时本身在诸如Double之类的api中完成的。通过NumberFormatException和路径进行解析。通过InvalidPathException得到。
Given you've written a component that validates Number strings for Double.ParseDouble
, maybe using a Regex, maybe a hand-written parser, or perhaps something that embeds some other domain rules that restricts the range of a double to something specific, how best to test this component? I think an obvious test would be to assert that, when the resulting string is parsed, no exception is thrown. I would write that test using either the above assertDoesNotThrow
or /*comment*/{code}
block. Something like
给你写一个组件来验证字符串数量翻倍。使用Regex ParseDouble,也许,也许一个手写的解析器,或者一些嵌入其他域规则限制对某些具体的双重的范围,如何测试这个组件?我认为一个明显的测试是断言,当生成的字符串解析,没有异常。我会写测试使用上述assertDoesNotThrow或/ *注释* / } {代码块。类似的
@Test public void given_validator_accepts_string_result_should_be_interpretable_by_doubleParseDouble(){
//setup
String input = "12.34E+26" //a string double with domain significance
//act
boolean isValid = component.validate(input)
//assert -- using the library 'assertJ', my personal favourite
assertThat(isValid).describedAs(input + " was considered valid by component").isTrue();
assertDoesNotThrow(() -> Double.parseDouble(input));
}
I would also encourage you to parameterize this test on input
using Theories
or Parameterized
so that you can more easily re-use this test for other inputs. Alternatively, if you want to go exotic, you could go for a test-generation tool (and this). TestNG has better support for parameterized tests.
我也鼓励你这个测试的参数输入使用理论或参数化,这样你可以更容易地重用这个测试对其他输入。另外,如果你想去异国情调的,你可以去测试生成工具(这)。TestNG具有更好的支持参数化测试。
What I find particularly disagreeable is the recommendation of using @Test(expectedException=IllegalArgumentException.class)
, this exception is dangerously broad. If your code changes such that the component under test's constructor has if(constructorArgument <= 0) throw IllegalArgumentException()
, and your test was supplying 0 for that argument because it was convenient --and this is very common, because good generating test data is a surprisingly hard problem--, then your test will be green-bar even though it tests nothing. Such a test is worse than useless.
我发现特别令人不快的是使用@Test(expectedException=IllegalArgumentException.class)的推荐,这个异常非常广泛。如果你的代码更改,这样被测试的组件的构造函数如果(constructorArgument < = 0)扔IllegalArgumentException(),和你的测试是为这一观点提供0,因为它是方便的,这是很常见的,因为好的生成测试数据是一个非常困难的问题,那么您的测试将绿条,尽管它没有测试。这样的测试比没用的还要糟糕。
#4
16
If you are unlucky enough to catch all errors in your code. You can stupidly do
如果您不幸捕获了代码中的所有错误。你愚蠢的可以做
class DumpTest {
Exception ex;
@Test
public void testWhatEver() {
try {
thisShouldThroughError();
} catch (Exception e) {
ex = e;
}
assertEquals(null,ex);
}
}
#5
9
With AssertJ fluent assertions 3.7.0:
使用AssertJ fluent断言3.7.0:
Assertions.assertThatCode(() -> toTest.method())
.doesNotThrowAnyException();
#6
2
Use assertNull(...)
使用assertNull(…)
@Test
public void foo() {
try {
//execute code that you expect not to throw Exceptions.
} catch (Exception e){
assertNull(e);
}
}
#7
2
You can do it by using a @Rule and then call method reportMissingExceptionWithMessage as shown below: This is Scala, but it can easily be done similarly in Java.
您可以使用@Rule,然后调用method reportMissingExceptionWithMessage,如下所示:这是Scala,但是在Java中也可以很容易地实现。
#8
1
If you want to test that whether your test target consumes the exception. Just leave the test as (mock collaborator using jMock2):
如果您想测试您的测试目标是否使用了异常。让测试保持为(使用jMock2的模拟合作者):
@Test
public void consumesAndLogsExceptions() throws Exception {
context.checking(new Expectations() {
{
oneOf(collaborator).doSth();
will(throwException(new NullPointerException()));
}
});
target.doSth();
}
The test would pass if your target does consume the exception thrown, otherwise the test would fail.
如果您的目标确实使用抛出的异常,则测试将通过,否则测试将失败。
If you want to test your exception consumption logic, things get more complex. I suggest delegating the consumption to a collaborator which could be mocked. Therefore the test could be:
如果您想测试异常消耗逻辑,事情就会变得更加复杂。我建议把消费委托给一个可以被嘲笑的合作者。因此,测试可以是:
@Test
public void consumesAndLogsExceptions() throws Exception {
Exception e = new NullPointerException();
context.checking(new Expectations() {
{
allowing(collaborator).doSth();
will(throwException(e));
oneOf(consumer).consume(e);
}
});
target.doSth();
}
But sometimes it's over-designed if you just want to log it. In this case, this article(http://java.dzone.com/articles/monitoring-declarative-transac, http://blog.novoj.net/2008/09/20/testing-aspect-pointcuts-is-there-an-easy-way/) may help if you insist tdd in this case.
但有时是过度设计的,如果你只是想需要进行日志记录。在这种情况下,这篇文章(http://java.dzone.com/articles/monitoring-declarative-transac,http://java.dzone.com/articles/monitoring-declarative-transac)可以帮助在这种情况下如果你坚持tdd。
#9
1
JUnit5 adds the assertAll() method for this exact purpose.
JUnit5为此目的添加了assertAll()方法。
assertAll( () -> foo() )
来源:JUnit 5 API
#10
0
The following fails the test for all exceptions, checked or unchecked:
以下是检查或不检查的所有异常的测试失败:
@Test
public void testMyCode() {
try {
runMyTestCode();
} catch (Throwable t) {
throw new Error("fail!");
}
}
#11
0
You can expect that exception is not thrown by creating a rule.
你可以认为不是通过创建一个规则抛出异常。
@Rule
public ExpectedException expectedException = ExpectedException.none();