Issue 83: Support @Rule/@ClassRule annotation on methods as well as fields
Matthew Farwell <[email protected]> Sat, 10 Sep 2011 22:59:34 +0200
| Newsgroups | gmane.comp.java.junit.devel |
|---|---|
| Message-ID | <CAOBkoFVLjGBu6KbfJL7kQNj+Xd7v592w83F40vK1upnuU=vGLg@mail.gmail.com> |
--===============9150440815820391547==
Content-Type: multipart/alternative; boundary=0016e64082bc389ee104ac9c92cf
--0016e64082bc389ee104ac9c92cf
Content-Type: text/plain; charset=ISO-8859-1
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.
--0016e64082bc389ee104ac9c92cf
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Hello,<div><br></div><div>I came across this issue (<a href=3D"https://gith=
ub.com/KentBeck/junit/issues/83">https://github.com/KentBeck/junit/issues/8=
3</a>)=A0recently, and I've created a fork & patch for it, but befo=
re I submit the pull request, I wanted to check with the development list t=
o see if I've done the correct thing, and because this is the first con=
tribution I've done for junit.</div>
<div><br></div><div>The problem is this: Scala does not support the creatio=
n 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 access=
ors. Therefore, it is impossible to use @Rule annotations correctly. So, fo=
r instance, the following code throws a initializationError ("Field th=
rown must be public"):</div>
<div><br></div><div><div>import org.junit._</div><div><br></div><div><div>c=
lass ClassTest {</div><div>=A0 @Rule val thrown =3D ExpectedException.none(=
)</div><div><br></div><div>=A0 @Test</div><div>=A0 def badInt: Unit =3D {</=
div><div>
=A0 =A0 thrown.expect(classOf[NumberFormatException])</div><div>=A0 =A0 Int=
eger.parseInt("one")</div><div>=A0 }</div><div>}</div></div></div=
><div><br></div><div>even though everything looks correct from the point of=
view of the developer (Scala fields and methods are public by default). On=
e solution would be to allow non-public fields to be used for @Rule annotat=
ions, but this was rejected in (<a href=3D"https://github.com/KentBeck/juni=
t/issues/31">https://github.com/KentBeck/junit/issues/31</a>). Another solu=
tion to this problem is to allow the @Rule annotation to apply to methods a=
s well. So, in java, you'd have:</div>
<div><br></div><div><div>public class ExampleTest {</div><div><span class=
=3D"Apple-tab-span" style=3D"white-space:pre"> </span>private ExpectedExcep=
tion thrown =3D=A0ExpectedException.none();</div><div><span class=3D"Apple-=
tab-span" style=3D"white-space:pre"> </span></div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>@Rule=
</div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span=
>public TestRule getThrown() {</div><div><span class=3D"Apple-tab-span" sty=
le=3D"white-space:pre"> </span>return thrown;</div>
<div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </span>}</di=
v><div><br></div><div><span class=3D"Apple-tab-span" style=3D"white-space:p=
re"> </span>@Test</div><div><span class=3D"Apple-tab-span" style=3D"white-s=
pace:pre"> </span>public void badInt() {</div>
<div><div>=A0 =A0 =A0 =A0 =A0 =A0 thrown.expect(NumberFormatException.class=
);</div><div>=A0 =A0 =A0 =A0 =A0 =A0 Integer.parseInt("one");</di=
v></div><div><span class=3D"Apple-tab-span" style=3D"white-space:pre"> </sp=
an>}</div><div>}</div></div>
<div><br></div><div>and Scala:</div><div><br></div><div><div>class ClassTes=
t {</div><div>=A0 private val vthrown =3D ExpectedException.none()</div><di=
v>=A0 @Rule def thrown() =3D vthrown</div><div><br></div><div>=A0 @Test</di=
v><div>
=A0 def badInt: Unit =3D {</div><div>=A0 =A0 vthrown.expect(classOf[NumberF=
ormatException])</div><div>=A0 =A0 Integer.parseInt("one")</div><=
div>=A0 }</div><div>}</div></div><div><br></div><div>To keep things consist=
ent, @ClassRule is also applicable to methods.</div>
<div><br></div><div>This is the change that I've made. It is available =
as a branch on my fork of junit @ github:=A0<a href=3D"https://github.com/m=
atthewfarwell/junit/commit/c82458623b1dd5ed65d4f59e6f2b769f1338e13d">https:=
//github.com/matthewfarwell/junit/commit/c82458623b1dd5ed65d4f59e6f2b769f13=
38e13d</a></div>
<div><br></div><div>The main change is to=A0BlockJUnit4ClassRunner#getTestR=
ules() and ParentRunner#classRules(). After creating the list of TestRule f=
rom 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 o=
rder is still undefined.</div>
<div><br></div><div>Validation for the @Rule annotated methods is as you wo=
uld expect, the methods must be public and return a TestType. In the case o=
f @ClassRule, it must also be static.</div><div><br></div><div>Could I plea=
se have some feedback on this: tell me if it fits in with the current direc=
tion of junit development, and if it is an acceptable feature?</div>
<div><br></div><div>I am completely open to any suggestions or criticisms o=
f my code.</div><div><br></div><div>Thanks.</div><div><br></div><div>Matthe=
w Farwell.</div><div><br></div>
--0016e64082bc389ee104ac9c92cf--
--===============9150440815820391547==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
------------------------------------------------------------------------------
Malware Security Report: Protecting Your Business, Customers, and the
Bottom Line. Protect your business and customers by understanding the
threat from malware and how it can impact your online business.
http://www.accelacomm.com/jaw/sfnl/114/51427462/
--===============9150440815820391547==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Junit-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/junit-devel
--===============9150440815820391547==--