Java EE 6 - Embedded container EJB tests

2019-03-14 03:52发布

问题:

This questiong is regarding Java EE 6, using glassfish v3 embedded-all.

I have a unit test that uses EJBContainer to test my stateless EJB. Problem is I'm having trouble looking up the EJB (remote) using JNDI:

setup() {

  ctx = EJBContainer.createEJBContainer().getContext();

}

...

test() {

BookService bookService = (BookService)ctx.lookup("java:global/BookServiceEJB!com.something.service.BookService");

...

}

@Stateless
public class BookServiceEJB implements BookService {
...
}

@Remote
public interface BookService {
...
}

gives the exception:

javax.naming.NamingException: Lookup failed for 'java:global/BookServiceEJB!com.something.service.BookService' in SerialContext  [Root exception is javax.naming.NameNotFoundException: BookServiceEJB!com.something.service.BookService not found]

...

caused by: javax.naming.NameNotFoundException: BookServiceEJB!com.something.service.BookService not found

I have tried several JNDI resource paths:

e.g.

java:global/BookServiceEJB

java:global/BookService

even:

java:global/BookShelf-1.0-SNAPSHOT/BookServiceEJB

etc...

nothings works

I do not have any xml deployment files configured, only a persistence.xml in META-INF.

The test is using maven surefire:

mvn clean test

Any help is greatly appreciated!

Note: a full deploy to Glassfish server works (using appclient, and @EJB injection)

回答1:

After much searching, found the solution that works for me...

You'll have to configure the EJBContainer with the property: EJBContainer.MODULES, and the location where the module classes are (if using maven, 'target/classes').

e.g.

...
props = new Properties();
props.put(EJBContainer.MODULES, new File("target/classes"));
ec = EJBContainer.createEJBContainer(props);
...

If your EJB uses JPA, theres another problem in that you will not be able to define a datasource in the embedded container, so have to use the default ds: 'jdbc/__default'.

so for example my persistence.xml looks like so:

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
    version="1.0">

    <persistence-unit name="bookshelf" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.blah.domain.Book</class>
        <jta-data-source>jdbc/__default</jta-data-source>
        <properties>
            <property name="eclipselink.logging.level" value="INFO"/>
        </properties>
    </persistence-unit>

</persistence> 

I haven't figured out how to configure the embedded container test to use one DS (jdbc/__default), and my app to use another (e.g. jdbc/booksDS)

see: http://www.mentby.com/glassfish/embedded-testing-woes.html

see: http://forums.java.net/jive/thread.jspa?messageID=395759

To be honest I don't know why people are bothering with Java EE when solutions like spring is so much simpler...

It has been very frustrating and alot of time wasted... hope this helps.



回答2:

There's a few items you need to check in order to make sure you can load the bean through the context.lookup avoiding a NamingException.

  1. Make sure you have a bean. This may sound something obvious but I spent a lot of time trying to figure out why I wasn't able to get an instance of my service in the tests. The reason was that I was missing the Stateless annotation.

  2. Add the module when creating the container as @Dzhu pointed out. For maven classes will be target/classes, for maven tests will be target/test-classes.

  3. Something is wrong if you find a message like SEVERE: EJB6005:No EJB modules found in the console. It tells you that there are no Stateless annotated classes

  4. Take a look at the embedded glassfish console! In there you will see the lookup names for your beans. Pay attention to the messages in the format INFO: EJB5181:Portable JNDI names for EJB YourBean: [java:global/classes/YourBean!bean.package.YourBean, java:global/classes/YourBean]. That means you can lookup your bean either by calling context.lookup("java:global/classes/YourBean!bean.package.YourBean") or by the shorter name context.lookup("java:global/classes/YourBean") which can be useful if there's no name collisions.

Hope this helps someone. It would have been really helpful to have had this tips.



回答3:

I have written a small tutorial on using the embedded glassfish 3.1 container, also addressing the issue for needing a different persistence.xml for tests. Also fixing container crashes with remote interfaces and webservices. You can check it out at http://pschyska.blogspot.com/2011/06/unit-testing-ejb-31-with-netbeans-maven.html