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&#39;ve created a fork &amp; patch for it, but befo=
re I submit the pull request, I wanted to check with the development list t=
o see if I&#39;ve done the correct thing, and because this is the first con=
tribution I&#39;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 (&quot;Field th=
rown must be public&quot;):</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(&quot;one&quot;)</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&#39;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(&quot;one&quot;);</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(&quot;one&quot;)</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&#39;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==--