JUnit 用于具有 Void 返回值的函数
我一直在开发一个 Java 应用程序,我必须使用 JUnit 进行测试。我边走边学。到目前为止,我发现它很有用,特别是与 Eclipse JUnit 插件结合使用时。
经过一番尝试后,我开发了一种一致的方法来为没有返回值的函数构建单元测试。我想在这里分享并请其他人发表评论。您有任何建议的改进或替代方法来实现相同的目标吗?
常见返回值
首先,有一个枚举用于存储表示测试结果的值。
public enum UnitTestReturnValues
{
noException,
unexpectedException
// etc...
}
通用测试
假设正在编写单元测试:
public class SomeClass
{
public void targetFunction (int x, int y)
{
// ...
}
}
将创建 JUnit 测试类:
import junit.framework.TestCase;
public class TestSomeClass extends TestCase
{
// ...
}
在此类中,我创建一个函数,用于对正在测试的目标函数的每次调用。它捕获所有异常并根据结果返回一条消息。例如:
public class TestSomeClass extends TestCase
{
private UnitTestReturnValues callTargetFunction (int x, int y)
{
UnitTestReturnValues outcome = UnitTestReturnValues.noException;
SomeClass testObj = new SomeClass ();
try
{
testObj.targetFunction (x, y);
}
catch (Exception e)
{
UnitTestReturnValues.unexpectedException;
}
return outcome;
}
}
JUnit 测试
JUnit 调用的函数以函数名称中的小写“test”开头,并且在第一次失败的断言时失败。要对上面的 targetFunction 运行多个测试,可以写成:
public class TestSomeClass extends TestCase
{
public void testTargetFunctionNegatives ()
{
assertEquals (
callTargetFunction (-1, -1),
UnitTestReturnValues.noException);
}
public void testTargetFunctionZeros ()
{
assertEquals (
callTargetFunction (0, 0),
UnitTestReturnValues.noException);
}
// and so on...
}
如果您有任何建议或改进,请告诉我。请记住,我正在学习如何使用 JUnit,因此我确信现有的工具可以使这个过程变得更容易。谢谢!
I've been working on a Java application where I have to use JUnit for testing. I am learning it as I go. So far I find it to be useful, especially when used in conjunction with the Eclipse JUnit plugin.
After playing around a bit, I developed a consistent method for building my unit tests for functions with no return values. I wanted to share it here and ask others to comment. Do you have any suggested improvements or alternative ways to accomplish the same goal?
Common Return Values
First, there's an enumeration which is used to store values representing test outcomes.
public enum UnitTestReturnValues
{
noException,
unexpectedException
// etc...
}
Generalized Test
Let's say a unit test is being written for:
public class SomeClass
{
public void targetFunction (int x, int y)
{
// ...
}
}
The JUnit test class would be created:
import junit.framework.TestCase;
public class TestSomeClass extends TestCase
{
// ...
}
Within this class, I create a function which is used for every call to the target function being tested. It catches all exceptions and returns a message based on the outcome. For example:
public class TestSomeClass extends TestCase
{
private UnitTestReturnValues callTargetFunction (int x, int y)
{
UnitTestReturnValues outcome = UnitTestReturnValues.noException;
SomeClass testObj = new SomeClass ();
try
{
testObj.targetFunction (x, y);
}
catch (Exception e)
{
UnitTestReturnValues.unexpectedException;
}
return outcome;
}
}
JUnit Tests
Functions called by JUnit begin with a lowercase "test" in the function name, and they fail at the first failed assertion. To run multiple tests on the targetFunction above, it would be written as:
public class TestSomeClass extends TestCase
{
public void testTargetFunctionNegatives ()
{
assertEquals (
callTargetFunction (-1, -1),
UnitTestReturnValues.noException);
}
public void testTargetFunctionZeros ()
{
assertEquals (
callTargetFunction (0, 0),
UnitTestReturnValues.noException);
}
// and so on...
}
Please let me know if you have any suggestions or improvements. Keep in mind that I am in the process of learning how to use JUnit, so I'm sure there are existing tools available that might make this process easier. Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
确实,如果您使用 JUnit 3,并且正在测试方法中是否引发特定异常,则需要使用类似于上面定义的 try-catch 模式之类的内容。
但是:
1)我认为测试具有 void 返回值的方法然后检查异常还有很多事情:您的方法是否正确调用(可能是模拟的)依赖项?当使用不同的上下文或不同的依赖集等初始化类时,它的行为是否有所不同。通过包装对该方法的所有调用,您将很难更改测试的其他方面。
如果可以避免的话,我通常也反对添加代码和增加复杂性;我不认为在检查异常时在给定测试中放置 try/catch 并不是一种负担。
2) 切换到 JUnit 4!它可以轻松检查预期的异常:
It is true that if you are using JUnit 3, and you are testing whether a particular exception is thrown or not thrown within a method, you will need to use something like the try-catch pattern you define above.
However:
1) I'd argue that there is a lot more to testing a method with a void return value then checking for exceptions: is your method making the correct calls to (presumably mocked) dependencies; does it behave differently when the class is initialized with a different context or different sets of dependencies, etc. By wrapping all calls to that method, you make it hard to change other aspects of your test.
I'm also generally opposed to adding code and adding complexity if it can be avoided; I don't think it's a burden to have to put a try/catch in a given test when it's checking for exceptions.
2) Switch to JUnit 4! It makes it easy to check for expected exceptions:
如果有可能,您应该升级到 JUnit 4.x。
然后您的第一个示例可以重写为:
这里的优点是您可以删除
private UnitTestReturnValues callTargetFunction (int x, int y)
方法并使用 JUnit 对预期异常的内置支持。您还应该测试特定的异常。
If you have the possibility, you should upgrade to JUnit 4.x.
Then your first example can be rewritten to:
The advantage here is that you can remove you the
private UnitTestReturnValues callTargetFunction (int x, int y)
method and use JUnit's built in support for expecting exceptions.You should also test for specific exceptions instead.
看来您重新实现了 JUnit 的大部分内容:) 一般来说,您不需要这样做。您只需调用您想要调用的函数并比较结果即可。如果它抛出异常,JUnit 会为您捕获该异常并导致测试失败。如果您期望出现异常,则可以在使用 JUnit 4 时使用显式注释,也可以使用以下模式:
同样,如果 obj.DoSth() 抛出不同的异常,JUnit 将使测试失败。
综上所述,恐怕我认为您的方法过于复杂,抱歉。
Looks like you reimplemented most of JUnit :) In general you don't need to do it. You just call the function you want to call and compare results. If it throws an exception, JUnit will catch if for you and fail the test. If you expect an exception, either you can use the explicit annotation if you are using JUnit 4, or you can use the following pattern:
again, if obj.DoSth() throws a different exception JUnit will fail the test.
So to sum up, I am afraid I believe your approach is overcomplicated, sorry.
如果我错了,请纠正我。正如我从提供的代码中了解到的,您只是检查执行函数时是否存在异常。但实际上您并没有验证被调用的函数是否正确“工作”,除非发生错误时结束的唯一方法是例外。我建议编写像这样的附加测试:
并且 verifyTargetFunction 将实际检查调用 targetFunction 是否会进行预期的更改 - 让我们通过返回 true 或 false 来对数据库表进行说明。
希望有帮助。
干杯,
马库斯
please correct me if I am wrong. As I understood from the provided code you're only checking if there may be an exception while executing the function. But you're actually not verifying, if the called functions "works" correctly unless the only way to end in case of an error would be an exception. I suggest writing additional tests like this:
and the verifyTargetFunction would acutally check, if calling targetFunction would have made the expected changes - let's say to a database table by returning true or false.
Hope that helps.
Cheers,
Markus