How to Mock EJBs within Jakarta EE?

If you use Mockito as a Test Framework to test your Jakarta EE EJB classes this can be super easy or a horror. At least when you have some older code as the situation was when I run into an strange issue with NullPointerExceptions.

The point is that Mockito has changed massively between Version 4 and 5. And you’ll notice this when you just copy & paste a lot of test code from older projects. So first make sure that your Maven dependencies are up to date and you use at least Mocktio version 5.2.0

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.13.1</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>5.8.0</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-junit-jupiter</artifactId>
  <version>5.8.0</version> 
  <scope>test</scope>
</dependency>

As you can see I use not only mockito-core but also the new mocktio-junit-jupiter framework that we can use for testing more complex Java beans like EJBs.

If you test a simple pojo class you test code will still look like this:

package org.imixs.workflow.bpmn;

import java.util.List;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class TestBPMNModelBasic {

	OpenBPMNModelManager openBPMNModelManager = null;

  @Before
  public void setup()  {
    openBPMNModelManager = new OpenBPMNModelManager();
  }

  @Test
  public void testStartTasks() {
    List<Object> startTasks = openBPMNModelManager.findStartTasks(model, "Simple");
    Assert.assertNotNull(startTasks);	
  }
}

This is a fictive test example from our Imixs-Workflow project. What you can see here is that I use a simple pojo class (OpenBPMNModelManger) that I create with the constructor in the setup method. And this works all fine!

But if you try the same with EJB you may possible fail early by creating the EJB mocks. However Mocktio supports you in this with the new mockito-junit-jupiter framework in version 5.x.

Take a look at the following example testing a Jakarta EE EJB:

package org.imixs.workflow.engine;

import org.imixs.workflow.bpmn.OpenBPMNModelManager;
import org.imixs.workflow.exceptions.ModelException;
import org.junit.Assert;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
public class TestModelServiceNew {

  @Mock
  private DocumentService documentService;

  @InjectMocks
  ModelService modelServiceMock;

  @BeforeEach
  public void setUp() {
    MockitoAnnotations.openMocks(this);
    when(documentService.load(Mockito.anyString())).thenReturn(new ItemCollection());
  }

  @Test
  public void testGetDataObject() throws ModelException {
   OpenBPMNModelManager openBPMNModelManager = modelServiceMock.getOpenBPMNModelManager();
   Assert.assertNotNull(openBPMNModelManager); 
  }
}

I am using here the Annotation @ExtendWith(MockitoExtension.class) to prepare my test class for testing more complex EJB code and I inject my EJB service as a mock with the annotation @InjectMocks. I also use the annotation @Mock here to inject additional dependency classes used by my service.

This all looks fine and it works perfect!

But there is one detail in my second example which can be easily overseen! The @Test annotation of my test method is now imported by the mockito jupiter framework and no longer form the core junit framework!

...
import org.junit.jupiter.api.Test; // Important!
...

And this is the important change. If you oversee this new import you will run into NullPointerExceptions.

The reason for this issue is that Mockito doesn’t automatically create the ModelServiceMock object when you still use import org.junit.Test. This is because the annotation @InjectMocks is used in conjunction with JUnit 5 and Mockito Jupiter. So if you still use any of the usual JUnit 5 annotations like @BeforeEach or the @Test annotation of JUnit 5 you will have a mix between JUnit 4 and JUnit 5, which can lead to problems.

Also note: In this example that also the annotation @Before has changed to @BeforeEach. Mockito depends on this new annotation too and will not call the when call if the setup method is not annotated with @BeforeEach !

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.