From: Alistair I. <ai...@gm...> - 2009-10-19 10:06:14
|
Hi, list. Hope I'm not overstepping by just barging in like this. Anyway, I'm one of those early adopters of JUnit 4.7's new @Rules. As I use them more and more I've also been seeing the usefulness of class-level rules more and more. A concrete use case of mine is initializing a JPA (Hibernate) persistence context backed by an embedded Derby database, then using DbUnit to load fixtures and populate the database. Using JUnit 4.7, I'm able to accomplish the above using a single MethodRule that does everything for every test method. The performance drawback should be obvious—we need to initialize Derby DB, set up Hibernate JPA, scan for annotated classes and create the tables to match the entities for _every test method_. I've taken the liberty of forking, branching, and committing some changes to JUnit that allow for class-level rules. It's up on GitHub, and the meat of the changes are here: http://github.com/AlistairIsrael/junit/commit/79ef5a7e1d7fa144cc81c9414f4791aaea8b3d75 The gist of it: * Created the ClassRule interface that declares the apply(Statement, TestClass) method. * Modified ParentRunner to scan for fields that are a) annotated with @Rule, b) static, and c) implement ClassRule. * If any are found, then apply them in the order found, allowing them to append to the head of the Statement chain. * Modified BlockJUnit4ClassRunner so validation treats ClassRules appropriately, and only apply MethodRules in methodBlock() I've also added a ClassRulesTest to AllTests to verify the above. Using a local-build, I successfully refactored my specific use-case and split the compound rule into a separate ClassRule (set up Derby and Hibernate) and a MethodRule (load DbUnit fixtures). Not only are the resulting tests more efficient, this strategy lets each Rule to be used independently, even allows for mixing and matching of different database, JPA or fixtures providers. I have a few more ideas on where this can go, but I'd like to get some feedback first if this is something that's welcome or if you guys have another direction you think we should take. Thanks, - alistair -- http://alistairisrael.wordpress.com |
From: David S. <da...@sa...> - 2009-10-23 13:25:22
|
Alistair, I think class-level rules make a lot of sense. Do you think re-using the @Rule annotation is better than a new @ClassRule annotation? David On Mon, Oct 19, 2009 at 6:05 AM, Alistair Israel <ai...@gm...> wrote: > Hi, list. > > Hope I'm not overstepping by just barging in like this. Anyway, I'm > one of those early adopters of JUnit 4.7's new @Rules. > > As I use them more and more I've also been seeing the usefulness of > class-level rules more and more. > > A concrete use case of mine is initializing a JPA (Hibernate) > persistence context backed by an embedded Derby database, then using > DbUnit to load fixtures and populate the database. > > Using JUnit 4.7, I'm able to accomplish the above using a single > MethodRule that does everything for every test method. The performance > drawback should be obvious—we need to initialize Derby DB, set up > Hibernate JPA, scan for annotated classes and create the tables to > match the entities for _every test method_. > > I've taken the liberty of forking, branching, and committing some > changes to JUnit that allow for class-level rules. It's up on GitHub, > and the meat of the changes are here: > http://github.com/AlistairIsrael/junit/commit/79ef5a7e1d7fa144cc81c9414f4791aaea8b3d75 > > The gist of it: > * Created the ClassRule interface that declares the apply(Statement, > TestClass) method. > * Modified ParentRunner to scan for fields that are a) annotated > with @Rule, b) static, and c) implement ClassRule. > * If any are found, then apply them in the order found, allowing > them to append to the head of the Statement chain. > * Modified BlockJUnit4ClassRunner so validation treats ClassRules > appropriately, and only apply MethodRules in methodBlock() > > I've also added a ClassRulesTest to AllTests to verify the above. > > Using a local-build, I successfully refactored my specific use-case > and split the compound rule into a separate ClassRule (set up Derby > and Hibernate) and a MethodRule (load DbUnit fixtures). Not only are > the resulting tests more efficient, this strategy lets each Rule to be > used independently, even allows for mixing and matching of different > database, JPA or fixtures providers. > > I have a few more ideas on where this can go, but I'd like to get some > feedback first if this is something that's welcome or if you guys have > another direction you think we should take. > > Thanks, > - alistair > -- > http://alistairisrael.wordpress.com > > ------------------------------------------------------------------------------ > Come build with us! The BlackBerry(R) Developer Conference in SF, CA > is the only developer event you need to attend this year. Jumpstart your > developing skills, take BlackBerry mobile applications to market and stay > ahead of the curve. Join us from November 9 - 12, 2009. Register now! > http://p.sf.net/sfu/devconference > _______________________________________________ > Junit-devel mailing list > Jun...@li... > https://lists.sourceforge.net/lists/listinfo/junit-devel > |
From: Alistair I. <ai...@gm...> - 2009-10-23 14:08:53
|
On Fri, Oct 23, 2009 at 9:25 PM, David Saff <da...@sa...> wrote: > I think class-level rules make a lot of sense. Do you think re-using > the @Rule annotation is better than a new @ClassRule annotation? Hi, David. Thanks for the vote. In my branch, I didn't make a new @ClassRule annotation—just a new ClassRule interface that's analogous to MethodRule. ClassRule defines one method: Statement apply(Statement base, TestClass testClass); The same @Rule annotation is use to specify a static class rule: @Rule public static DerbyResource derbyResource = new DerbyResource(); The only thing I haven't done is let a static @Rule be _both_ a ClassRule _and_ a MethodRule—yet. I don't think it'll take much more to get there, though. - alistair -- http://alistairisrael.wordpress.com |
From: David S. <da...@sa...> - 2009-10-26 13:52:07
|
Alistair, [I need to try to remember "reply all" and CC junit-devel so that everyone stays involved; I keep forgetting] On Sat, Oct 24, 2009 at 10:02 PM, Alistair Israel <ai...@gm...> wrote: > On Fri, Oct 23, 2009 at 9:25 PM, David Saff <da...@sa...> wrote: > >> I think class-level rules make a lot of sense. Do you think re-using >> the @Rule annotation is better than a new @ClassRule annotation? > > Hi, again, David. > > Finally remembered another reason (in fact, my primary reason) for > reusing @Rule. > > While in some cases, separating a ClassRule from a MethodRule makes > sense (and allows for mixing and matching), in other cases that simply > breaks encapsulation. > > The basic case is an expensive factory object or setup code that's > used to provide a new instance of a resource to each @Test method. The > ClassRule performs "around Class" setup & teardown, but the MethodRule > would use the first to get new instance of the resource (which it uses > for "around @Test" behavior). > > Consider a remote Web service that's used to report test results and > timings to. (I know, it sounds contrived, but I don't want to keep > harping about my own embedded DB + JPA + dependency injection use > case.) > > The setup of the Web service is expensive, and ideally we'd want to > set it up once before all tests, and cleanup after everything's done. > Meanwhile, around each test we want to report start then > success/failure. > > We could separate the two using: > > @ClassRule > public static TestReportingWebService service = new > TestReportingWebService(); > > @Rule > public RemoteTestWatchman watchman = new RemoteTestWatchman(service); > > Or, in my mind it'd be nicer to be able to go: > > @Rule > public static RemoteTestWatchman watchman = new RemoteTestWatchman(); Note that we can get the "one object" behavior with the "two annotations" API: @ClassRule public static RemoteTestWatchman watchman = new RemoteTestWatchman(); @Rule public RemoteTestWatchman methodWatchman = watchman; Is this better? David |
From: Alistair I. <ai...@gm...> - 2009-10-26 23:55:36
|
On Mon, Oct 26, 2009 at 9:51 PM, David Saff <da...@sa...> wrote: > Note that we can get the "one object" behavior with the "two annotations" API: > > @ClassRule > public static RemoteTestWatchman watchman = new RemoteTestWatchman(); > > @Rule public RemoteTestWatchman methodWatchman = watchman; Well, yeah I suppose that would work. Or you could simply annotate the same field twice. I guess ultimately it's a design decision. Personally, I like having fewer annotations and letting the framework figure out my intent, following published 'conventions', if need be. I can see others, though, favoring explicit declarations of method-level rules vs. class-level rules. Since JUnit rules have only been out, oh, a couple of months(?) it remains to be seen how others might use them and prefer to handle class rules. I've given my opinions for the record. I don't see anything wrong with going either way and "failing fast"—after all, seeing the history of JUnit you guys haven't been loathe to introduce something then deprecate it soon enough afterward if something else made better sense. - alistair -- http://alistairisrael.wordpress.com |
From: David S. <da...@sa...> - 2009-10-27 12:57:31
|
If a feature is rarely used, I prefer forcing some verbosity on code writers in order to prevent surprises on the part of the readers. If a feature is often used enough that it becomes part of the "vernacular" of the library, then both writers and readers win with brevity. Of course, only by releasing something can we be sure how often it will be used. I'd like to go with the more verbose version. Would you like to incorporate that into your patch, or wait until Kent or I have time to do it? Thanks, David Saff On Mon, Oct 26, 2009 at 7:55 PM, Alistair Israel <ai...@gm...> wrote: > On Mon, Oct 26, 2009 at 9:51 PM, David Saff <da...@sa...> wrote: > >> Note that we can get the "one object" behavior with the "two annotations" API: >> >> @ClassRule >> public static RemoteTestWatchman watchman = new RemoteTestWatchman(); >> >> @Rule public RemoteTestWatchman methodWatchman = watchman; > > Well, yeah I suppose that would work. Or you could simply annotate the > same field twice. > > I guess ultimately it's a design decision. Personally, I like having > fewer annotations and letting the framework figure out my intent, > following published 'conventions', if need be. I can see others, > though, favoring explicit declarations of method-level rules vs. > class-level rules. > > Since JUnit rules have only been out, oh, a couple of months(?) it > remains to be seen how others might use them and prefer to handle > class rules. > > I've given my opinions for the record. I don't see anything wrong with > going either way and "failing fast"—after all, seeing the history of > JUnit you guys haven't been loathe to introduce something then > deprecate it soon enough afterward if something else made better > sense. > > - alistair > -- > http://alistairisrael.wordpress.com > |
From: Alistair I. <ai...@gm...> - 2009-10-27 16:31:23
|
On Tue, Oct 27, 2009 at 8:57 PM, David Saff <da...@sa...> wrote: > I'd like to go with the more verbose version. Would you like to > incorporate that into your patch, or wait until Kent or I have time to > do it? Hi, David. Oh, I suppose I can wait. Meanwhile, I've dropped back to @BeforeClass in a base class. I figure an 'around' Category aspect will be the next thing I'll look out for. :) - alistair -- http://alistairisrael.wordpress.com |