10

This is the class I'm trying to test:

@Stateless
public class Finder {
  @PersistenceContext(unitName = "abc")
  EntityManager em;
  public String read(int i) {
    return this.em.find(Employee.class, i).getName();
  }
}

This is the unit test:

public class FinderTest {
  @Test public void testReadingWorks() {
    Finder f = new Finder();
    String name = f.find(1);
    assert(name.length() > 0);
  }
}

The problem is that EntityManager is not injected, and is NULL during testing. What am I doing wrong?

ps. Actually, I don't understand who exactly is going to inject EntityManager. The unit test is started by JUnit, outside of any container... Maybe I have to inject em manually in the test?

yegor256
  • 102,010
  • 123
  • 446
  • 597

2 Answers2

11

Injection of EntityManagers only works in managed beans, since you are creating the Finder with new no container is involved. You could eithere create the EntityManager yourself using the EntityManagerFactory or use a embeddable Container like OpenEJB in your unit tests.

Jörn Horstmann
  • 33,639
  • 11
  • 75
  • 118
6

Actually, I don't understand who exactly is going to inject EntityManager. The unit test is started by JUnit, outside of any container... Maybe I have to inject em manually in the test?

Since your test is running out container, nobody is going to inject anything, you'll have to do it manually. This is IMHO not really a bad thing, and not hard.

Out container

Here is a base class that you could extend to get an EntityManager:

public abstract class JpaBaseRolledBackTestCase {
    protected static EntityManagerFactory emf;
    protected EntityManager em;

    @BeforeClass
    public static void createEntityManagerFactory() {
        emf = Persistence.createEntityManagerFactory("PetstorePu");
    }

    @AfterClass
    public static void closeEntityManagerFactory() {
        emf.close();
    }

    @Before
    public void beginTransaction() {
        em = emf.createEntityManager();
        em.getTransaction().begin();
    }

    @After
    public void rollbackTransaction() {

        if (em.getTransaction().isActive()) {
            em.getTransaction().rollback();
        }

        if (em.isOpen()) {
            em.close();
        }
    }

}

In container using the EJBContainer API

Another option would be to run your test in container, using the EJB 3.1 EJBContainer API to start an embedded container. See Arun's TOTD #128: EJBContainer.createEJBContainer: Embedded EJB using GlassFish v3 (you'll need a bit more work to setup the datasource).

In container using Arquillian

Or you could use Arquillian. Have a look at The perfect recipe for testing JPA 2: revisited for some ideas. I tested this approach this morning and find it VERY interesting for real integration tests (but in container tests are typically slower and I won't use them for everything - but I'm starting to love Arquillian).

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Just a note. If you are using Arquillian it is important running you TestClass or your Test itself **without** `@RunAsClient` else EntityManager won't be Injected. There is also an working exampla evailable: https://github.com/arquillian/arquillian-showcase/blob/master/jpa/src/test/java/com/acme/jpa/GamePersistenceTestCase.java – Tobias Sarnow Sep 06 '12 at 13:08
  • Sorry I know that it's an old discussion. Do you know why the EntityManager is not injected if @RunAsClient? Is there a way to have the EM anyway? – user1341300 Aug 04 '16 at 14:17