Testing an EJB with JUnit - jpa

How should I test an EJB 3.1 which gets an instance of EntityManager injected?
A possible EJB:
#Stateless
#LocalBean
public class CommentService {
#PersistenceContext
private EntityManager em;
public List<Comment> findAll() {
TypedQuery<Comment> query = em.createNamedQuery(
Comment.FIND_ALL, Comment.class
);
return query.getResultList();
}
}
A possible test:
#Test
public void testFindAll() {
List<Comment> all = service.findAll();
Assert.assertEquals(8, all.size());
}
I am only using GlassFish 3.1 and Eclipse Indigo for Java EE Developers. I already tried things like that:
#Before
public void setUp() throws Exception {
ejbContainer = EJBContainer.createEJBContainer();
service = (CommentService) ejbContainer.getContext()
.lookup("java:global/classes/CommentService");
}
But all I got was:
javax.ejb.EJBException:
No EJBContainer provider available: no provider names had been found.

The accepted answer requires mocking a lot of code, including the persistence layer. Use an embedded container to test the actual beans, instead; otherwise, mocking the persistence layer results in code that barely tests anything useful.
Use a session bean with an entity manager that references a persistence unit:
#Stateless
public class CommentService {
#PersistenceContext(unitName = "pu")
private EntityManager em;
public void create(Comment t) {
em.merge(t);
}
public Collection<Comment> getAll() {
Query q = em.createNamedQuery("Comment.findAll");
Collection<Comment> entities = q.getResultList();
return entities;
}
}
The entity bean:
#Entity
#NamedQueries({#NamedQuery(name = "Comment.findAll", query = "select e from Comment e")})
public class Comment implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
This persistence unit is defined in the persistence.xml file as follows:
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="pu" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.glassfish.embedded.tempconverter.Comment</class>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
The transaction type must be JTA.
Then write a test that creates and destroys the EJB container (GlassFish embedded container):
public class CommentTest extends TestCase {
private Context ctx;
private EJBContainer ejbContainer;
#BeforeClass
public void setUp() {
ejbContainer = EJBContainer.createEJBContainer();
System.out.println("Opening the container" );
ctx = ejbContainer.getContext();
}
#AfterClass
public void tearDown() {
ejbContainer.close();
System.out.println("Closing the container" );
}
public void testApp() throws NamingException {
CommentService converter = (CommentService) ctx.lookup("java:global/classes/CommentService");
assertNotNull(converter);
Comment t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
t = new Comment();
converter.create(t);
Collection<Comment> ts = converter.getAll();
assertEquals(4, ts.size());
}
}
Next, add two dependencies (such as to a Maven POM):
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.glassfish.main.extras</groupId>
<artifactId>glassfish-embedded-all</artifactId>
<version>3.1.2</version>
<scope>compile</scope>
</dependency>
Having the dependencies, session and entity bean, persistence file, test files implemented exactly as shown, then the test(s) should pass. (The examples on the Internet are woefully inadequate.)

First of all, make sure you distinguish between unit tests and integration tests. JUnit is just a framework that helps you organize and run the tests, but you have to determine the scope of your tests.
I assume you're interested in defining a unit test of CommentService.findAll(). What does that mean? That means I'll verify that calling the findAll() method results in CommentService invoking the named query named by the FIND_ALL string constant.
Thanks to dependency injection and stubbing, you can easily achieve that using e.g. Mockito to stub out the EntityManager. For the unit test, we're only focusing on the business logic in findAll(), so I won't bother testing lookup of the Comment service either--testing that the Comment service can be looked up and is wired to a proper entity manager instance is in the scope of an integration test, not a unit test.
public class MyCommentServiceUnitTest {
CommentService commentService;
EntityManager entityManager;
#Before
public void setUp() {
commentService = new CommentService();
entityManager = mock(EntityManager.class);
commentService.setEm(entityManager); // inject our stubbed entity manager
}
#Test
public void testFindAll() {
// stub the entity manager to return a meaningful result when somebody asks
// for the FIND_ALL named query
Query query = mock(Query.class);
when(entityManager.createNamedQuery(Comment.FIND_ALL, Comment.class)).thenReturn(query);
// stub the query returned above to return a meaningful result when somebody
// asks for the result list
List<Comment> dummyResult = new LinkedList<Comment>();
when(query.getResultList()).thenReturn(dummyResult);
// let's call findAll() and see what it does
List<Comment> result = commentService.findAll();
// did it request the named query?
verify(entityManager).createNamedQuery(Comment.FIND_ALL, Comment.class);
// did it ask for the result list of the named query?
verify(query).getResultList();
// did it return the result list of the named query?
assertSame(dummyResult, result);
// success, it did all of the above!
}
}
With the unit test above, I tested the behavior of the findAll() implementation. The unit test verified that the correct named query is obtained and that the result returned by the named query was returned to the callee.
What's more, the unit test above verifies that the implementation of findAll() is correct independently of the underlying JPA provider and the underlying data. I don't want to test JPA and the JPA provider unless I suspect there are bugs in the 3rd party code, so stubbing out these dependencies lets me focus the test entirely on the business logic of the Comment service.
It can take a little while to adjust to the mindset of testing behavior using stubs, but it is a very powerful technique for testing the business logic of your EJB 3.1 beans because it lets you isolate and narrow the scope of each test to exclude external dependencies.

Why not using Arquillian to write even unit tests and run them in a real container!?
No more mocks. No more container lifecycle and deployment hassles. Just real tests!
Mocks can be tactical, but more often than not, they are used to make code work outside of a real environment. Arquillian let's you ditch the mocks and write real tests. That's because Arquillian brings your test to the runtime, giving you access to container resources, meaningful feedback and insight about how the code really works.
More about Arquillian features.

It's possible to write unit tests that run against a container, but the caveat is that the container/appserver has to be up. Since that's not really practical, the general approach is to use a "mock" container to run your unit tests against. For that, check out JUnitEE or ejb3unit:
junitee
ejb3unit

Related

Run method after deploying and save the result with to database

I have started a Quarkus project and i have there 2 tables, i am trying to run a Method immediately after deploying, In the method i use Entitymanger to save some results in the database.
In pure Jakarta EE, you could an EJB and annotate it with #Startup. But Since quarkus uses CDI.
#ApplicationScoped
public class StartApp {
private static final String PERSISTENCE_UNIT_NAME = "Employee";
public void init(#Observes #Initialized(ApplicationScoped.class) Object init) {
EntityManagerFactory factory =
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager em = factory.createEntityManager();
Directory directory = new Directory("/some/info", true, false, ".xml");
em.persist(directory);
em.close();
}
}
How can i do that!? some guess !
I think what you need is this:
#ApplicationScoped
class StartApp {
void startup(#Observes StartupEvent event) {
// Do whatever needs to be done.
}
}
More information and options can be found on the very well documented quarkus pages. https://quarkus.io/guides/cdi-reference#startup-event
Ps. don't forget about your transactions and maybe take a look at Hibernate ORM.

Extended Persistence Context with ViewScoped CDI beans

I am a long time Seam user who tries to move to Java EE7, JSF2.2 and CDI now.
In Seam you tend to use EntityManagers with extended scope most of the time (in the Seam Conversation Scope). You don't get any LIEs on Ajax request etc.
I am trying to do it in a similar way with Java EE7 and CDI but somehow the injected EntityManager is only transaction scoped. When I get a ajax request in the entities that were loaded before are not managed anymore.
I am using the new javax.faces.view.ViewScoped and javax.transactional.Transactional on my CDI bean.
My Producer:
#PersistenceContext(unitName = "primary", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#Produces
#Default
#Dependent
public EntityManager getEntityManager() {
return entityManager;
}
And my CDI bean:
#Named
#ViewScoped
#Transactional
public class TestBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Inject
EntityManager entityManager;
Logger log = Logger.getLogger(TestBean.class);
private TestEntity lastTest = null;
public void testAdd(){
TestEntity test = new TestEntity();
test.setVal("Test "+System.currentTimeMillis());
entityManager.persist(test);
entityManager.flush();
log.infov("Created test entity {0}", test);
lastTest = test;
}
public void testRead(){
List<TestEntity> test = entityManager.createQuery("select t from TestEntity t").getResultList();
for(TestEntity t: test){
log.infov("Found {0} managed {1}",t,entityManager.contains(t));
}
if(lastTest!=null){
log.infov("Last Test {0} managed {1}",lastTest,entityManager.contains(lastTest));
}
}
So when I first call testAdd() via Ajax it creates a new test entity. When I then call testRead() it gets all test entities and checks that the last created test entity is still managed (which it should if it is an EntityManager with an extended persistent context). But entityManager.contains(lastTest) always returns false.
What am I doing wrong?
I believe I can't use #PersistenceContext directly in the CDI bean. So how do I get the desired (Seam like) behaviour?
When you specify that an injected EntityManager is an extended persistence context, all object instances remain managed. Extended persistence contexts can only be used within Stateful session beans.
This is according to JBOSS documentation: https://docs.jboss.org/ejb3/app-server/tutorial/extended_pc/extended.html.
Consider packaging your insert/update/delete operations into EJBs while simple read from database can be through CDI beans. But more complex operations involving multiple reads and writes as well as transaction should be within EJBs.

Inject EntityManager in SwitchYard Junit implementation

I am trying to implement Junit in SwitchYard Application.
i am using JPA , without using Camel. i have persistence.xml with the following details. And i am using resource producer pattern to expose EntityManager.
But when i am testing a service, i am getting null Invocation for EntityManager in DAO layer.
Is there any way , i can mock or inject EntityManager in SwitchYard Junit
#RunWith(SwitchYardRunner.class)
#SwitchYardTestCaseConfig(config = SwitchYardTestCaseConfig.SWITCHYARD_XML, mixins = {
CDIMixIn.class, HTTPMixIn.class, NamingMixIn.class })
public class SalesModuleServiceTest {
private SwitchYardTestKit testKit;
private CDIMixIn cdiMixIn;
private HTTPMixIn httpMixIn;
private static NamingMixIn namingMixIn;
private TransformerRegistry transformerRegistry;
#ServiceOperation("SalesModuleService")
private Invoker service;
//------ JUnit test with REST binding fails if no resteasy properties defined ------
#BeforeDeploy
public void setProperties()
{
System.setProperty("org.switchyard.component.resteasy.standalone.port", "8081");
System.setProperty("org.switchyard.component.resteasy.standalone.path", "");
}
#Test
public void testUpdateCustomerStatus() throws Exception {
SalesDetailsRequest message = null;
BudgetResponse<?> result = service.operation("updateCustomerStatus")
.sendInOut(message).getContent(SalesResponse.class);
// validate the results
Assert.assertTrue("Implement me", false);
}
}

#ManyToOne(fetch=FetchType.LAZY) lazy loading not working

I am working with JPA 2.1 (EclipseLink 2.5.1) and JBoss 7.1.
I've define very simple JPA entities:
#Entity
#Table(name="APLICACIONES_TB")
public class Aplicacion implements Serializable {
#Id
#Column(name="COD_APLICACION_V")
private long codAplicacionV;
#Column(name="APLICACION_V")
private String aplicacionV;
#OneToMany(mappedBy="aplicacion")
private Collection<Prestacion> prestaciones;
... getters and setters
}
#Entity
#Table(name="PRESTACIONES_TB")
public class Prestacion implements Serializable {
#Id
#Column(name="COD_PRESTACIONES_V")
private String codPrestacionesV;
#Column(name="DESCRIPCION_V")
private String descripcionV;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "COD_APLICACION_V")
private Aplicacion aplicacion;
... getters and setters ...
}
I have developed a staless EJB that executes a query to obtain some "Aplicacion" entities.
#Stateless
#LocalBean
public class DocuEJB implements DocuEJBLocal
{
#PersistenceContext(name="DocuEjb", type=PersistenceContextType.TRANSACTION)
private EntityManager em;
public Prestacion getResult(String name)
{
return em.createNamedQuery("ExampleQueryName", Prestacion.class).getSingleResult();
}
}
Because I'm working with JSF 2.1 the EJB is being injected in a managed bean:
#ManagedBean(name = "ManagedBean")
#RequestScoped
public class ManagedBean
{
#EJB DocuEJB docuEjb;
public String doSomething()
{
Prestacion entity = docuEjb.getResult("egesr");
if (entity != null)
{
// It should return null because 'entity' should be detached
Aplicacion app = entity.getAplicacion();
// but 'app' entity is not null, ¿why not?
System.out.println (app.getCodAplicacionV());
}
}
}
Lazy loading is not working even when lazy loading has been defined for 'aplicacion' field on 'Prestacion' entity. The code posted before should return a NullPointerException in the next line:
System.out.println (app.getCodAplicacionV());
because 'app' entity is detached and lazy loading has been configured.
Why is not working lazy loading?
Thanks
Try to add #Transactional on doSomething(), I think that your transaction manager is not well configured.
You can see here the official spring documentation. In any case, can you add your spring configurations, so that we can better help you. :)
I don't think the behavior your encounter is abnormal or your question should state it clearly:
EJB are by default transactional
Your JSF inject an EJB, with #EJB, and I guess JBoss can create a java reference and not a proxy
The entity is being managed because the transaction is not done, it will finish when doSomething ends.
Your entity is then loaded into the EntityManager, and lazy loading works because there is a context to it.
You would call em.evict(entity) with the result your are getting, this would probably fails because the entity would not be managed any more.

Entity states between EJB and Jersey

I'm a novice.
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
The primary target usage is JTA.
#Stateless
class MyEJB {
public MyEntity find(Long id) {
...
}
#PersistenceContext;
EntityManager entityManager;
}
class MyResource {
#GET
#Path("/myentity/{id}");
public MyEntity get(#PathParam("id") final long id) {
final MyEntity found = myEjb.find(id);
// is found's state detached?
// should I have to reattach?
found.setDate(new Date());
return found;
}
#EJB
private MyEjb myEjb;
#PersistenceContext;
EntityManager entityManager;
}
Does Jersey and EJB hold the same EntityManager scope?
Should I have to pass the EntityManager to EJB for same persistence context?
I don't think that your wording is correct, but they can share the same EntityManager instance, and you have chosen the right way (through injection). Have a look at this chapter of the Java EE 6 Tutorial:
To obtain an EntityManager instance, inject the entity manager into the application component:
#PersistenceContext
EntityManager em;
So, once again, your approach is correct. With regards to the questions in the code comments: the fact that MyEntity is attached or detached, it depends on the implementation of the find method in your EJB. If you do the following, it will be attached:
public MyEntity find(Long id) {
return entityManager.find(MyEntity.class, id);
}
Finally, doing this way, if you have chosen JTA to use container managed transactions, the transactions will be automatically bounded with the natural boundaries of MyBean's methods. In order to have JTA transactions, you have to use this line in persistence.xml file:
<persistence-unit name="em" transaction-type="JTA">