JUnit 4 的 @Suite,传递数据,@Rule 并弃用 @Before 和 @After
我正在使用一些遗留测试代码,这些代码利用 TestSetup 类来围绕包含测试的类测试套件设置和拆卸服务器。我已将类转换为使用 junit 注释,并尝试使用 @Suite 和 @Suite.Classes 注释来定义套件。但我已经碰壁了。
旧版本的测试扩展了 TestSetup,以循环遍历所有实例化的测试类,并将对服务器对象的各种引用注入其中。一个示例是对 Spring 框架 Web 上下文的引用。
我的问题是,使用注释我无法看到如何在执行测试之前将夹具数据传递到实例化的测试类。
我研究了新的 @Rule 和 MethodRule 技术,但(坦率地说)它们似乎是一个复杂但有限的解决方案,解决了一个不太清楚的问题。无论如何,我不知道他们如何解决我的问题。另一个问题是,JUnit 作者似乎打算最终从 JUnit 中删除 @Before/@After 概念。
那么有谁知道如何将数据从用 @Suite 注释的类传递到 Suite 类运行的每个测试?
I'm working with some legacy test code which makes use of a TestSetup class to setup and teardown a server around a test suite of classes containing tests. I've converted the classes to use junit annotations and have attempted to use the @Suite and @Suite.Classes annotations to define the suite. But I've hit a wall.
The old version of the tests extend TestSetup to loop through all the instantiated test classes and inject various references to server objects into them. An example being a reference to the Spring framework web context.
My problem is that using the annotations I cannot see how to pass fixture data to the instantiated test classes before the tests are executed.
I've looked into the new @Rule and MethodRule techniques, but (frankly) they just appear to be a complex, but limited solution to a problem that's not really clear. Anyway, I could not see how they could solve my problem. An additional concern being that it would appear that the JUnit authors are intent on eventually removing the @Before/@After concept from JUnit.
So does anyone know how to pass data from a class annotated with @Suite to each test that the Suite class runs?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
众所周知,JUnit4 风格的测试套件比 JUnit3 风格的测试套件受到更多限制。我听说过有关此问题的投诉,但不知道官方有解决方案。我认为可能有一些第三方解决方案试图解决这个问题。关于您的特定问题,我认为您无法从 JUnit4 样式套件访问测试实例,因为 JUnit4 在方法运行之前实例化测试。
最简单的方法是继续使用 JUnit3 风格的套件。它们应该可以与 JUnit4 一起正常运行。管理共享资源的一个缺点是
套件的缺点是您不能再单独运行测试类。另一方面,如果测试类无论如何都需要一起运行(也许以特定的顺序),那么它可能是一个有效的解决方案。
另一种方法是从内到外解决共享资源问题:在您的情况下,测试类将使用 @Rule 声明它们需要服务器存在。第一次执行规则时,它会启动服务器,将相关信息保存在静态字段中,并执行准备测试所需的任何操作。例如,它可以注入一些测试的字段,或者它可以只允许测试使用规则的 API 来获取它需要的信息。下次执行该规则时,它会跳过“启动服务器”步骤。是的,静态是邪恶的,但有时它是绕过 JUnit 限制的唯一方法。 (这里我不会触及使用其他测试框架的主题。)由
内而外方法的一大优点是它允许您直接运行测试类(无需通过套件)并且彼此独立。缺点是它可能更难以实现,并且很难拆除非内存资源(在您的情况下:关闭服务器)。要完成后者,您必须使用 JVM 关闭挂钩,因为 JUnit 不提供足够的回调。尽管这可能会起作用(因为构建工具和 IDE 通常为每个测试运行使用单独的 JVM),但它仍然很丑陋。
第三种方法是让您的 Ant/Maven/Gradle/任何构建在运行测试之前/之后设置/拆除公共资源。同样,这种方法不如由内而外的方法灵活和方便,并且带来了如何将信息从构建传递到运行测试的 JVM(如果需要)的问题。 Maven Cargo 插件 是这种方法的典型示例。
最后但并非最不重要的一点是,您可以尝试务实一点,每个测试类启动/停止服务器一次。这实现起来非常简单,但可能适合也可能不适合您的情况(例如,它可能太耗时)。
规则是编写模块化和可重用 JUnit 扩展的一种方法。比使用基类好得多,因为基类很快就会遇到单一继承问题。这对于发布 JUnit 扩展的库来说更为重要。
你从哪里听说的?您是否会将其与 xUnit.net 混淆,后者强烈建议不要使用 setup/teardown 方法?无论如何,在测试之前或之后执行某些操作是规则最重要的用例之一,所以我认为您不应该担心。
JUnit4-style test suites are known to be more limited than JUnit3-style test suites. I've heard complaints about this but am not aware of an official solution. I think there might be some third-party solutions that try to tackle this problem. Regarding your particular problem, I don't think you can get access to the test instances from a JUnit4-style suite, because JUnit4 instantiates a test right before the method gets run.
The simplest way out would be to continue using the JUnit3-style suites. They should run fine with JUnit4. One drawback of managing shared resources with
a suite is that you can't run the test classes separately anymore. On the other hand, if the test classes need to be run together anyway (maybe in a particular order), it may be a valid solution.
Another approach is to tackle the shared resources problem inside-out: In your case, test classes would declare with a @Rule that they need the server to be present. The first time the rule gets executed, it starts the server, keeps relevant information in static field(s), and does whatever is necessary to prepare the test. For example it could inject some of the test's fields, or it could just allow the test to use the rule's API to get at the information it needs. The next time the rule gets executed, it skips the "start server" step. Yes, static state is evil, but it's sometimes the only way to get around JUnit's limitations. (I won't touch the subject of using other testing frameworks here.)
The big advantage of the inside-out approach is that it allows you to run test classes directly (without going through the suite) and independently from each other. The drawback is that it can be more difficult to implement, and that it makes it hard to tear down non-memory resources (in your case: shutting down the server). To accomplish the latter, you will have to use a JVM shutdown hook because JUnit doesn't provide an adequate callback. Although this will probably work (because build tools and IDEs typically use a separate JVM for each test run), it is nevertheless ugly.
A third approach is to let your Ant/Maven/Gradle/whatever build set up/tear down common resources before/after running the tests. Again, this is less flexible and convenient than the inside-out approach, and brings up the question of how to pass information from the build to the JVM that's running the tests (if necessary). The Maven Cargo plugin is a typical example for this approach.
Last but not least, you could try to be pragmatic and start/stop the server once per test class. This is very simple to implement, but may or may not be adequate in your situation (e.g. it might be too time-consuming).
Rules are a way to write modular and reusable JUnit extensions. Much better than using base classes, where you will soon hit the single inheritance problem. This is even more relevant for libraries shipping JUnit extensions.
Where did you hear that? Aren't you confusing this with xUnit.net, which strongly discourages the use of a setup/teardown method? Anyway, performing some action before or after a test is one of the most important use cases for rules, so I don't think you should be concerned.
JUnit 4.9 正在以构建器的形式为此提供更好的解决方案,但我认为在此之前解决此问题的最干净(尽管有点难以实现)的方法是创建一个自定义 Runner 实现(扩展现有的实现之一) 。 @Peter 说得很对,Suite 创建相对于 JUnit 3.8 有弱点,尽管它也有一些优点。
JUnit 4.9 is cooking a better solution for this in the form of a builder, but I think before then the cleanest (although a bit difficult to implement) way to address this is to make a custom Runner implementation (extend one of the existing ones). @Peter is quite right that Suite creation has weak points over JUnit 3.8, although it also has some strong points.