On Jun 30, 2011, at 12:27 PM, kubamarchwicki wrote:

> 
> Romain Manni-Bucau wrote:
>> 
>> if i remember i wrote an abstract class for testng
>> 
>> https://issues.apache.org/jira/browse/OPENEJB-1526

Check that in!  That's great.  Having not done a lot of work in TestNG I simply 
had no idea how to accomplish the same thing.  That looks great and we can 
probably refactor things internally for a little more reuse.

Side note to Jakub on the ApplicationComposer.  What we're doing internally is 
adding your test case to the app as a bean and deploying it.  It is effectively 
the same as creating an inner-class bean to drive testing.  The method-level 
services that beans get are not there yet (see the last section below), but 
100% of the dependency injection that an EJB can get a test case can get too.  
This is true of ApplicationComposer or use of the EJBContainer API (also 
detailed below).

And in terms of third-party frameworks offering this dependency injection and 
"portability" to test cases, I admit I scratch my head a little bit.  
Dependency injection is Inversion of Control and Inversion of Control is 
already all about portability.  It is invisible by definition and the entire 
point is that you *don't* see or have a dependency on who is doing the 
injection.  Your only dependency is on the things you need injected -- your 
stuff.  So who really cares who is doing the injection -- the container itself 
or a third-party test framework that pulls the stuff from the container and 
puts it in.  Neither is less or more "portable" and ultimately what you can get 
injected boils down to what the container you are testing with supports.

The only real question of portability is in the bootstrapping process.  The 
EJBContainer API is currently the only spec standard bootstrapping mechanism we 
have and is only the start.  All vendors have no choice but to support it if 
they want to be a certified Java EE implementation -- full profile or web 
profile.  The more we as an industry adopt it, the more requirements we demand 
from it, the more things evolve and the more features get added back into spec. 
 The innovation of a few vendors get pushed back onto all the vendors and the 
level of portability increases.

The idea of a third-party framework that does the testing integration work for 
the vendor, taking on the work of creating and maintaining an adapter for each 
popular platform, is certainly interesting and can no doubt move a little 
quicker.  But I question its ability to persist over time.  It's a lot to 
maintain and there is no incentive for vendors to be anything but lazy.  
Regardless, I applaud either approach -- any step forward is a good one.  It's 
beyond wonderful to see what can only be described as a testing renaissance 
happening in Java EE.

People typically don't test Spring components without Spring and if things were 
that easy in Java EE (via any means) people wouldn't dream of the Do It 
Yourself approach.  It all boils down to speed and convenience.  We're finally 
taking concrete steps down that path in Java EE.

> Romain, that looks like an absolute class! I'll give it a try and share my
> experience as a follow up to the articles I've already written. I've already
> tried with JUnit and I'm excited about the results. The test are running few
> times faster (no need to bootstrap persistence unit on every test for
> example). I must admit that's something I've been looking for.

Right.  And in trunk (OpenEJB 4.0) we've married this with the EJBContainer API 
which basically gives you the same "build your app" functionality without any 
test framework specific things.  Since it is not testing specific, you could 
use it in any kind of standalone app.  Small example of manually creating one 
little bean in a jar:

   
http://svn.apache.org/repos/asf/openejb/trunk/openejb3/container/openejb-core/src/test/java/org/apache/openejb/OpenEjbContainerTest.java

Note that also shows injection of the class who bootstrapped the EJBContainer 
API.  You can actually get that without the cast to OpenEjbContainer by just 
calling `EJBContainer.createEJBContainer().getContext().bind("inject", this);`  
Nearly all our examples in trunk have been ported to the EJBContainer API:

   http://ci.apache.org/projects/openejb/examples-generated/   (this little 
tool is two weeks young and still a work in progress)

Standardly that API has a couple ways to disable the classpath scan (the magic 
part).  You can pass String, String[], File or File[] as the value of the 
`javax.ejb.embeddable.modules` property of the 
`javax.ejb.embeddable.EJBContainer` API.

  - String, String[] = the module name(s) you want deployed.  Module name is as 
defined by the Java EE 6 rules: defaults to the directory or jar name sans the 
extension, but can be explicitly set in the related descriptor via the 
`<module-name>` element
  - File, File[] = the actual file paths of the modules you want deployed.

That still might get you more than you want -- allows you to identify modules, 
but doesn't allow you to be more specific and select individual components.  I 
hope at some point there is a standard way we can do that, but in the meantime 
we do have some extensions to the `javax.ejb.embeddable.modules`.

Alternatively, we will allow you to pass in any of the descriptor trees we 
understand -- these are the same as supported by ApplicationComposer.  
Currently supported in 4.0.0-SNAPSHOT:
  
  - EjbJar
  - EnterpriseBean (convenience shorthand of EjbJar)
  - Application
  - Connector
  - Persistence
  - PersistenceUnit (convenience shorthand of Persistence)
  - Beans (aka cdi beans.xml, not well known yet)

Don't yet have support for collections of these things, but that will be there 
before final version.  With the ApplicationComposer you can just have several 
@Module methods and pass back any of the above, so building a larger app is 
easy.  Certainly passing a List<Object> as the value of 
"javax.ejb.embeddable.modules" will be supported.  But since there's already a 
Map being passed as the value of `EJBContainer.createEJBContainer`, there's no 
reason to cram everything into one key and instead we could just allow you to 
`map.put("myModule", ejbJar);`

Not supported yet as a `javax.ejb.embeddable.modules` value, but we will add 
before final and is something I would really like to add in EJB 3.2 as a 
standard part of the EJBContainer API is:

  - Class, Class[] = just give us the class(es) directly.  Skip the scrape and 
hand them right to us.  We'll treat them as if we "found" them on the 
classpath.  Nice thing is no vendor-specific objects and anyone should be able 
to support it.  Could be of limited use without descriptor data, but with a 
little clever thinking we can probably find a way to work that in.  A simple 
class that wraps Class[] and URL[] (the descriptors) would do the trick.  
Anytime you introduce a new type on a spec level it is hard to keep people 
focused on keeping things simple, but we might be able to pull it off.  Getting 
the `javax.ejb.embeddable.EJBContainer` API in there at all was quite the feat 
and only possible because of the maturity of the InitialContext approach we had 
proven works.  Obviously a lot more is required beyond that simple API, but 
getting the entire industry to agree to support embedded EJB Containers is a 
game-changing step forward.

Summary: all of the above pertains to just plain old 
`javax.ejb.embeddable.EJBContainer` API which is not testing specific.  Applies 
to any EJB development where you simply do not want a server or would prefer to 
work in a plain Java SE environment.


Back in the testing world, there are more interesting things that can be done 
besides skipping the scrape and building apps in code.  Specifically, if EJB as 
an environment offers services like transactions and security that can be 
declared on individual methods of beans, why not let tests do the same?  Why 
not allow people to specify with an annotation on their test method if they 
need a transaction or not, or if the test should be executed as a particular 
role.  This is all in the experimental stage, but indicative of what we'd like 
to see in next.next. gen testing:

  // Run each test as a specific role and do your own pass/fail checking
  
http://svn.apache.org/repos/asf/openejb/trunk/openejb3/container/openejb-junit/src/test/java/org/apache/openejb/junit/TestEjbSecurityRunTestAs.java

  // Run each test N times and have the framework do the pass/fail checking
  
http://svn.apache.org/repos/asf/openejb/trunk/openejb3/container/openejb-junit/src/test/java/org/apache/openejb/junit/TestEjbSecurity.java

Obviously, this starts to really get at some of what makes integration testing 
hard which is dealing with combinations of factors.  EJB as a concept tries to 
take the complexity of several real world factors out of code (security, 
transactions, etc).  Unless there is some equally easy way to express these 
factors in tests, the complexity winds up in the testing code.  The two need to 
be at the same level.

Anyway, it's a huge evolving topic we're obviously very passionate about.  
Hoping to use much of the above for documentation -- we need it -- and you're 
more than welcome to use any of it as well in your writings -- we need help 
there too :)


-David

Reply via email to