Mocking Entitymanager while testing of EJB class - java

I am using: Netbeans, Glassfish, Mockito
While working with Java EE for the first time I have come across the issue of trying to test methods that interact with the database using an entitymanager.
In the below code snippets I have tried to mock out the entity manager so i know that the db interaction will not be tested exactly and for this testing thats ok. But I am striggling on instansiating the UsersController because it has an injected EntityManager which is always null. I would like the EntityManager to be mocked out so I can test the rest of the method.
Below is a class that interacts with the db. NOTE this is an example methods, it is not for use in production.
#Stateless
public class UsersController {
#PersistenceContext()
EntityManager em;
public User getOne() {
em.getEntityManagerFactory().getCache().evictAll();
User theUser = null;
try {
Query q = em.createNamedQuery("User.findAll");
Collection<User> entities = q.getResultList();
theUser = Iterables.get(entities, 1);
}
catch(NoResultException e){}
em.flush();
return theUser;
};
}
The test file that will test this method.
#RunWith(MockitoJUnitRunner.class)
public class UsersControllerTest {
#Mock
private UsersController usersController;
#Mock
private EntityManager entityManagerMock;
private Collection<User> mockUsersDbCollection = //...
#BeforeClass
public void setUpClass() {
when(entityManagerMock.createNamedQuery("User.findAll")).thenReturn(mockUsersDbCollection);
}
#Test
public void findOneTest(){
User mockUserDbEntry = new User("1", "pa$$word", "salt", "user1", "user1#email.com", false);
User returnedUser = null;
returnedUser = usersController.getOne();
assertEquals(returnedUser.getId(), "1");
}
}
Whenever the UsersController mock is created the entityManager is always null causing issues, how can I inject the EntityManagerMock so it will work?

You have a few issues here:
you are testing your UsersController, therefore it should not be mocked; rather you should use the #InjectMocks annotation on it because you want Mockito to inject your mock entity manager
the #BeforeClass annotation only works when applied to a static method, which in turn can only access static instance variables; in this instance I think you just need the #Before annotation
your entityManagerMock.createNamedQuery needs to return a mock Query object, the code you pasted should not even compile
In the end, your test should look something like:
#RunWith(MockitoJUnitRunner.class)
public class UsersControllerTest {
#InjectMocks
private UsersController usersController;
#Mock
private EntityManager entityManagerMock;
#Mock
private EntityManagerFactory entityManagerFactory;
#Mock
private Cache emfCache;
#Mock
private Query findAllQuery;
private List<User> mockUsersDbCollection = //...
#Before
public void setUp() {
when(entityManagerFactory.getCache())
.thenReturn(emfCache);
when(entityManagerMock.getEntityManagerFactory())
.thenReturn(entityManagerFactory);
when(entityManagerMock.createNamedQuery("User.findAll"))
.thenReturn(findAllQuery);
when(findAllQuery.getResultList())
.thenReturn(mockUsersDbCollection);
}
#Test
public void findOneTest(){
mockUsersDbCollection.add(new User("1", "pa$$word", "salt", "user1", "user1#email.com", false));
User returnedUser = usersController.getOne();
assertEquals(returnedUser.getId(), "1");
}
}

Related

Mockito when isn't replacing original method behaviour

I got 2 modules User and Email, both of them have 1 entry point which is a facade, rest is package scoped. The configuration is done in 2 classes
#Configuration
class UserConfiguration {
#Bean
UserFacade userFacade(UserRepository repository, EmailFacade emailFacade) {
return new UserFacade(repository, emailFacade);
}
}
#Configuration
class EmailConfiguration {
#Bean
EmailFacade emailFacade(EmailSender emailSender) {
return new EmailFacade(emailSender);
}
}
Now, I want to write tests that don't require Spring to start. I implemented a simple InMemoryRepository to make this happen
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade = new EmailFacade(new FakeEmailSender());
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I need some fake objects to instantiate EmailFacade so I wrote fake implementation
public class FakeEmailSender implements EmailSender {
#Override
public void sendEmail(EmailMessage emailMessage) throws RuntimeException {
}
}
In that scenario, I'm testing User domain, so I want to mock Email anyways.
I wrote a test to check if it works
#Test
public void shouldReturnSendingFailed() {
Mockito.when(emailFacade.sendUserVerificationEmail(Mockito.any())).thenReturn(Either.left(EmailError.SENDING_FAILED));
assertThat(userFacade.registerNewUser(RegisterUserDto.builder()
.username(USERNAME_4)
.email(VALID_EMAIL)
.password(VALID_PASSWORD).build()).getLeft(), is(EmailError.SENDING_FAILED));
}
But it isn't... after running this test I got
java.util.NoSuchElementException: getLeft() on Right
edit#
regiserNewUser() method
Either<DomainError, SuccessMessage> register(RegisterUserDto registerUserDto) {
if(userRepository.findUser(registerUserDto.getUsername()).isPresent())
return Either.left(UserError.USERNAME_ALREADY_EXISTS);
var userCreationResult = User.createUser(registerUserDto);
var savedUser = userCreationResult.map(this::saveUser);
var emailDto = savedUser.map(this::createVerificationEmail);
return emailDto.isRight() ? emailFacade.sendUserVerificationEmail(emailDto.get())
: Either.left(emailDto.getLeft());
}
Edit2#
With following test configuration
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
#InjectMocks
private UserFacade userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
}
I got nullpointer here, last line of registerNewUser().
Try running this code
#RunWith(MockitoJUnitRunner.class)
public class RegisterUserTest {
#Mock
private EmailFacade emailFacade;
private UserFacade userFacade;
#Before
public void setUp() {
userFacade = new UserConfiguration().userFacade(new InMemoryUserRepository(), emailFacade);
}
}
There are a few issues with your code:
You initialize your mocks twice. You don’t need to call initMocks in the setUp method if you are using Mockito runner
You are trying to inject mocks to already initialized object. But the field you are trying to inject is also passed to the constructor. Please read #InjectMocks doc, to check the strategies used to inject the mocks:
constructor (not used here, already initialized object)
setter (do you have one?)
field (is it not final)
There are details to each strategy (see my questions above). If no staregy is matched, Mockito will fail silently. The fact that you are passing an object in constructor, and rely on setter or field injection afterwards makes this code unnecesarily complex.

Unit Tests How to Mock Repository Using Mockito

I am having an issue with stubbing my repository. I was suggested to just create another application.properties (which I have not done) and to use an in-memory database like H2. I was wondering though if I can just stub the call so when myDataService.findById(id) is called instead of it attempting to get that from the database just a mocked object can be returned?
I am new to writing mocks for my unit tests and spring boot in general so maybe I am missing something. Code below (tried to simplify and made names generic for posting here).
My test class
public class MyServiceImplTest
{
private MyDataService myDataService;
private NyService myService;
private MyRepository myRepository;
#Before
public void setUp() {
myDataService = Mockito.mock(MyDataServiceImpl.class);
myService = new MyServiceImpl(myDataService);
}
#Test
public void getById_ValidId() {
doReturn(MyMockData.getMyObject()).when(myDataService).findById("1");
when(myService.getById("1")).thenReturn(MyMockData.getMyObject());
MyObject myObject = myService.getById("1");
//Whatever asserts need to be done on the object myObject
}
}
Class used for making the service call to the data layer
#Service
public class MyServiceImpl implements MyService {
MyDataService myDataService;
#Autowired
public MyServiceImpl(MyDataService myDataService) {
this.myDataService = myDataService;
}
#Override
public MyObject getById(String id) {
if(id == null || id == "") {
throw new InvalidRequestException("Invalid Identifier");
}
MyObject myObj;
try {
myObj = myDataService.findById(id);
}catch(Exception ex) {
throw new SystemException("Internal Server Error");
}
return myObj;
}
}
This is where I am having the issue in my test. When the findById() method is called, the variable repository is null so when trying to do repository.findOne(id) it throws an exceptionn. This is what I am attempting to mock, but the repository is giving me issues.
#Repository
#Qualifier("MyRepo")
public class MyDataServiceImpl {
#PersistenceContext
private EntityManager em;
private MyRepository repository;
#Autowired
public MyDataServiceImpl(MyRepository repository) {
super(repository);
this.repository = repository;
}
public MyObject findById(String id) {
P persitentObject = repository.findOne(id);
//Calls to map what persitentObject holds to MyObject and returns a MyObject
}
}
Code for MyRepository here just to show it's an empty interface that extends CrudRepository
public interface MyRepository extends CrudRepository<MyObjectPO, String>, JpaSpecificationExecutor<MyObjectPO> {
}
Let me begin by saying you are on the right track by using Constructor Injection and not Field Injection(which makes writing tests with mocks much simpler).
public class MyServiceImplTest
{
private MyDataService myDataService;
private NyService myService;
#Mock
private MyRepository myRepository;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this); // this is needed for inititalizytion of mocks, if you use #Mock
myDataService = new MyDataServiceImpl(myRepository);
myService = new MyServiceImpl(myDataService);
}
#Test
public void getById_ValidId() {
doReturn(someMockData).when(myRepository).findOne("1");
MyObject myObject = myService.getById("1");
//Whatever asserts need to be done on the object myObject
}
}
The call goes all the way from your service --> dataService. But only your repository calls are mocked.
This way you can control and test all the other parts of your classes(both service and dataService) and mock only repository calls.

Test Spring-Boot Repository interface methods without touching the database using Mockito

I have the following test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
public class TransactionServiceTests {
#Rule
public MockitoRule mockitoRule = MockitoJUnit.rule();
#Mock
private MessagingService mockMessagingService;
#Mock
private CustomerRepository mockCustomerRepository;
#Autowired
TransactionService transactionService;
#Test
public void testTransactionBetweenCustomersAndBalanceOfReceiver() {
int AMOUNT = 50;
// prepare your test data unless you always expect those values to exist.
Customer customerReceiver = new Customer();
customerReceiver.setName("TestReceiver");
customerReceiver.setBalance(12);
mockCustomerRepository.save(customerReceiver);
Customer customerSender = new Customer();
customerSender.setName("TestSender");
customerSender.setBalance(50);
mockCustomerRepository.save(customerSender);
int expectedReceiverAmount = customerReceiver.getBalance() + AMOUNT;
int expectedSenderAmount = customerSender.getBalance() - AMOUNT;
transactionService.makeTransactionFromSenderToReceiver(customerSender, customerReceiver, AMOUNT);
assertEquals(expectedSenderAmount, customerSender.getBalance());
assertEquals(expectedReceiverAmount, customerReceiver.getBalance());
}
}
This is the TransactionService. class itself:
#Service
public class TransactionService {
private MessagingService messagingService;
private CustomerRepository customerRepository;
private static final Logger log = LoggerFactory.getLogger(TransactionService.class);
#Autowired
public TransactionService(MessagingService messagingService, CustomerRepository customerRepository){
Assert.notNull(messagingService, "MessagingService cannot be null");
this.messagingService = messagingService;
Assert.notNull(customerRepository, "CustomerRepository cannot be null");
this.customerRepository = customerRepository;
}
public void makeTransactionFromSenderToReceiver(Customer sender, Customer receiver, int amount) {
if (sender.getBalance() >= amount) {
sender.setBalance(sender.getBalance() - amount);
receiver.setBalance(receiver.getBalance() + amount);
customerRepository.save(sender);
customerRepository.save(receiver);
}
else {
throw new RuntimeException();
}
}
}
During the test, it is adding the above mentioned users to my live database and leaving them there even after the tests are finished. Can I in some way tell Mockito to not touch my database? Or is that totally not possible?
"Mock" your repository method calls. Also, use #InjectMocks instead #Autowired for TransactionService. And you can also use MockitoJUnitRunner.
How to mock repository calls:
when(customerRepository.save(sender)).thenReturn(someSenderInstance);
To verify that mocked method call has been invoked use:
verify(customerRepository, times(1)).save(sender);
Also, remember one thing: You are testing services! Therefore, all calls to database should be mocked.
As suggested by JB Nizet, just because you define a mock instance in a test doesn't mean all objects will start using that mock instance. To achieve the behaviour you want to achieve, you need to use #InjectMocks on the class you are testing which in your case is TransactionService. To understand the difference between #Mock and #InjectMocks , refer to this question difference between #Mock and #InjectMocks

Mocked Method is throwing NullPointerException in Mockito

This is my test class
#RunWith(MockitoJUnitRunner.class)
public class ServiceTest extends Service{
#Mock
EntityManager eman = Mockito.mock(EntityManager.class);
#Mock
Query query;
#InjectMocks
private Service service;
private static final String NAME = "name";
#Before
public void setUp() {
this.service=new Service();
}
#Test
public void firstMethodTest() {
Query query = mock(Query.class);
when(
eman.createNamedQuery(NAME)).thenReturn(query);
when
( query.setParameter("name", Type)).thenReturn(query);
when (query.getSingleResult()).thenReturn(type);
**service.getAllMethod(1, "string");**
assertSame(/*Something to compare */);
}
}
This is my Service Class method
public getAllMethod(int ID, String string)
{
Query query=em
.createNamedQuery("name");
**query.setParameter("string", Type);**
type= query.getSingleResult();
}
When service.getAllMethod(1, "String") is invoked from Mocked Object ,I am getting NPE at query.setParameter("name", Type) because I think query is still NULL. Kindly Assume that My Service is working fine.
Thanks in Advance
While debugging I check the value of Query query in service class.Its value is null.Cant figure out how to resolve this issue.
You are recreating your Service before every test. So the Service that Mockito is injecting the mocks into has been lost.
Get rid of the setUp method and, instead, declare service like this:
#InjectMocks
private Service service = new Service();
There are some other things wrong too. e.g. The EntityManager Mockito.mock isn't required, the test class shouldn't be extending Service, the #Mock Query isn't being used.
Here's a rough template to start with:
#RunWith(MockitoJUnitRunner.class)
public class TestA {
#Mock
EntityManager eman;
#InjectMocks
private Service service = new Service();
#Test
public void firstMethodTest() {
Query query = Mockito.mock(Query.class);
Mockito.when(eman.createNamedQuery(NAME)).thenReturn(query);
service.getAllMethod(1, "string");
}
}
Assuming Service is something like:
public class Service {
#Autowired
EntityManager entityManager;
public void getAllMethod(int i, String s) {
Query q = entityManager.createNamedQuery("name");
... q isn't null here for me
}
}

JPA EntityManager blocks after #Transactional method

I have a Spring-JUnit test with a setup method that uses JPA Entities to setup test data. Within the test itself, legacy code uses JDBC-Templates to query the inserted test data. When the legacy code issues a query, the call to jdbcTemplate.query(...) hangs.
My Unit Test looks like this:
#TransactionConfiguration(defaultRollback = false)
#ContextConfiguration(locations = { "/testContext.xml" })
#Transactional
public class MyTest {
#PersistenceContext(unitName = "someUnit")
private EntityManager entityManager;
#Test
public void test() {
// here some legacy Code is called that uses JDBC Templates to query
// the inserted test data. The legacy code hangs upon jdbcTemplate.query(...)
}
#Before
public void before() {
this.entityManager.persist(new Entity1(...));
this.entityManager.persist(new Entity2(...));
}
}
My question is: Why doesn't the enitymanager commit upon exiting the before() method? Or does it commit and immediately start a new transaction, that still references the stored entity? I also tried to do without the junit annotation #Before annotation and manually call the before() method. But this gives the same result.
Any advice is highly appreciated.
Test class
#ContextConfiguration(locations = { "/testContext.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
#RunWith(SpringJUnit4ClassRunner.class)
#Transactional
public class MyTest extends AbstractTransactionalJUnit4SpringContextTests{
#PersistenceContext(unitName = "someUnit")
private EntityManager entityManager;
#Autowired
private BeforeService beforeService;
#Test
public void test() {
beforeService.before();
// here some legacy Code is called that uses JDBC Templates to query
// the inserted test data. The legacy code hangs upon jdbcTemplate.query(...)
}
}
Before Service
public class BeforeService {
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(final EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void before() {
entityManager.persist(new Entity1(...));
entityManager.persist(new Entity2(...));
}
}
I hope I've given you all the answers about your question.

Categories

Resources