2

I am using the Mockito framework for my jUnit testing. I am not able to fetch data from the database. Fetches null or empty from the db. Not sure how can I mock the entityManager.

public class AppServiceTest  {

    @Mock
    private EntityManager entityManager;    
    @Mock 
    DataSource mockDataSource;
    @Mock 
    Connection mockConn;
    @Mock 
    PreparedStatement mockPreparedStmnt;
    @Mock 
    ResultSet mockResultSet;    
    @Mock
    private Query query;

    @Test
    public void testGetAllDc() throws NamingException {        

        AppDataService appDataService  = Mockito.mock(AppDataService.class); 
        List<String> customResults = new ArrayList<String>();
        //customResults = ....
        System.out.println("**RESULTS**"+appDataService.getAllDc());              // here it is printed as []
        Mockito.when(appDataService.getAllDc()).thenReturn(customResults);
        }
    }

AppDataService.java:

@Stateless
public class AppDataService{

   @PersistenceContext
   EntityManager entityManager;

     public List<Object> getAllDc() {
       try {
         Query query = entityManager.createQuery("myQuery");
         List<String> allDc= query.getResultList();
         }
         //......   
   }

Update: Its observed that the mock values can be detected for entityManager as Mock for EntityManager, hashCode: 5425710. But entityManager.getCriteriaBuilder() or whatever entityManager.get....() are getting null in the AppDataService class .

Jonathan
  • 20,053
  • 6
  • 63
  • 70
Nidheesh
  • 4,390
  • 29
  • 87
  • 150
  • is it just me or you are trying to mock every class in the test? is this a unit test or an integration test? if unit test, have you tried with DBUnit? – germanio Apr 27 '16 at 18:14
  • I am new to junit. I need to test my DAO methods. Do we need to hit the database in the test method as well to make sure that the db fetch is working properly. – Nidheesh Apr 28 '16 at 03:54
  • Cool. So if you need to test your DAO methods, mock the DB with DBunit. That will run much faster than connecting with the real thing, allowing the dev team to write code and test it, and also you won't depend on the state of an external resource to make your unit tests pass, which is extremely helpful. Then the next step will be integration tests, running in a properly configured environment. – germanio Apr 28 '16 at 18:21

2 Answers2

2

In your test, you create a mock AppDataService appDataService = Mockito.mock(AppDataService.class);.

In order to test this class, you must not mock it. Either create it using new AppDataService() or let mockito do that for you (@InjectMocks)

To initialize the mocks or the class-under-test you may do this by using annotations and either use the mockito runner:

@RunWith(MockitoJunitRunner.class)
public class AppServiceTest  {

   @InjectMock
   private AppService appService;

   @Mock
   private EntityManager entityManager;

or

@Before
public void setup() {
  MockitoAnnotations.initMocks(this);
}

Further, you mocked entitymanager, therefore all of it's methods are stubbed and return no values (null) per default on any method call.

If you expect the createQuery("myQuery") invocation to return something, you should stub it properly after mock creation/injection in the setup method.

@Before
public void setup() {
  //... 
  when(entityManager.createQuery(eq("myQuery"))).thenReturn(query); 
  //OR
  when(entityManager.createQuery(anyString())).thenReturn(query) 

If it doesn't matter what the mocks return as long as it is not null, you may initialize the mocks using

@Mock(answer = Answers.RETURNS_DEEP_STUBS)) //OR @Mock(answer = Answers.RETURNS_MOCKS)
private EntityManager entityManager;

So the whole test should look like

@RunWith(MockitoJunitRunner.class)
public class AppServiceTest  {

  @Mock(answer = Answers.RETURNS_DEEP_STUBS)) 
  private EntityManager entityManager;    
  @Mock
  private Query query;

  ...
  @InjectMocks
  private AppDataService appDataService;

  @Test
  public void testGetAllDc() throws NamingException {        

     //arrange
     List<String> customResults = new ArrayList<String>();
     //TODO populate customResults
     when(entityManager.createQuery("myQuery")).thenReturn(query);
     when(query.getResultList()).thenReturn(customResults);

     //act
     System.out.println("**RESULTS**"+appDataService.getAllDc()); 
Gerald Mücke
  • 10,724
  • 2
  • 50
  • 67
  • try `when(entityManager.createQuery(eq("myQuery"))).thenReturn(query)` or `when(entityManager.createQuery(anyString())).thenReturn(query)` and if you use @InjectMocks and @Mock annotations, run the test with `MockitoJUnitRunner` or invoked MockitoAnnotations.initMocks(this) before configuring the mocks – Gerald Mücke Apr 21 '16 at 06:15
  • Thanks. Its observed that the mock values can be detected for `entityManager` as `Mock for EntityManager, hashCode: 5425710`. But `entityManager.getCriteriaBuilder()` or whatever `entityManager.get....()` are getting null in the `AppDataService` class . Any idea what is missing. – Nidheesh Apr 21 '16 at 09:29
  • either you have to declare the behaviour of *every single method* that you intend to invoke, using the `when(...` method. You might as well initialize the mock with deep stubs (`@Mock(answer = Answers.RETURNS_DEEP_STUBS)`) or mocks (`@Mock(answer = Answers.RETURNS_MOCKS)`), and then only inject special behavior where needed. – Gerald Mücke Apr 21 '16 at 11:12
1

You don't need to mock appDataService if you want to test it. This field should be annotated with @InjectMocks.

@InjectMocks
private AppDataService appDataService = new AppDataService();

What you need to mock is entityManager.createQuery and query.getResultList methods.

Query queryMock = mock(Query.class);
when(entityManager.createQuery(anyString())).thenReturn(queryMock);
when(query.getResultList()).thenReturn(customResults);

After taht you can call appDataService.getAllDc() in your test and check the results.

Sergii Bishyr
  • 8,331
  • 6
  • 40
  • 69