From: Matthew F. <ma...@fa...> - 2011-09-10 20:59:41
|
Hello, I came across this issue (https://github.com/KentBeck/junit/issues/83) recently, and I've created a fork & patch for it, but before I submit the pull request, I wanted to check with the development list to see if I've done the correct thing, and because this is the first contribution I've done for junit. The problem is this: Scala does not support the creation of public fields. When you define a field with a public access modifier, this gets implemented in the bytecode as a private field with public accessors. Therefore, it is impossible to use @Rule annotations correctly. So, for instance, the following code throws a initializationError ("Field thrown must be public"): import org.junit._ class ClassTest { @Rule val thrown = ExpectedException.none() @Test def badInt: Unit = { thrown.expect(classOf[NumberFormatException]) Integer.parseInt("one") } } even though everything looks correct from the point of view of the developer (Scala fields and methods are public by default). One solution would be to allow non-public fields to be used for @Rule annotations, but this was rejected in (https://github.com/KentBeck/junit/issues/31). Another solution to this problem is to allow the @Rule annotation to apply to methods as well. So, in java, you'd have: public class ExampleTest { private ExpectedException thrown = ExpectedException.none(); @Rule public TestRule getThrown() { return thrown; } @Test public void badInt() { thrown.expect(NumberFormatException.class); Integer.parseInt("one"); } } and Scala: class ClassTest { private val vthrown = ExpectedException.none() @Rule def thrown() = vthrown @Test def badInt: Unit = { vthrown.expect(classOf[NumberFormatException]) Integer.parseInt("one") } } To keep things consistent, @ClassRule is also applicable to methods. This is the change that I've made. It is available as a branch on my fork of junit @ github: https://github.com/matthewfarwell/junit/commit/c82458623b1dd5ed65d4f59e6f2b769f1338e13d The main change is to BlockJUnit4ClassRunner#getTestRules() and ParentRunner#classRules(). After creating the list of TestRule from the @Rule annotated fields, it calls all of the @Rule annotated methods and adds the TestRule objects returned to the list of TestRule. This means that if a field and method are annotated with @Rule, then the field comes first, then the method. However, if multiple fields are defined, then the order is still undefined. Validation for the @Rule annotated methods is as you would expect, the methods must be public and return a TestType. In the case of @ClassRule, it must also be static. Could I please have some feedback on this: tell me if it fits in with the current direction of junit development, and if it is an acceptable feature? I am completely open to any suggestions or criticisms of my code. Thanks. Matthew Farwell. |