using JPA2 for an entity update - jpa-2.0

I'm not really used to JPA... so this is more like a basic question
I use JPA2 - (not hibernate)
I have this function, and I want to make an update on my
#RequestScoped // (this is javax.faces.bean.RequestScoped)
#Stafeful // (this is javax.ejb.Stateful)
public class MyProvider {
#Inject
private EntityManager entityManager;
/* some variables and getters and setters */
public void setLocked(Long id, boolean locked) {
entityManager.getTransaction().begin();
user = userProvider.findUserByID(id);
user.setLocked(locked);
entityManager.persist(user);
// i also tried it with refresh instead of persist
entityManager.refresh(user);
entityManager.getTransaction().commit();
}
}
but i get this error at this point
entityManager.getTransaction().begin();
java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
org.hibernate.ejb.AbstractEntityManagerImpl.getTransaction(AbstractEntityManagerImpl.java:996)
org.jboss.as.jpa.container.AbstractEntityManager.getTransaction(AbstractEntityManager.java:498)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.jboss.weld.util.reflection.SecureReflections$13.work(SecureReflections.java:264)
org.jboss.weld.util.reflection.SecureReflectionAccess.run(SecureReflectionAccess.java:52)
org.jboss.weld.util.reflection.SecureReflectionAccess.runAsInvocation(SecureReflectionAccess.java:137)
org.jboss.weld.util.reflection.SecureReflections.invoke(SecureReflections.java:260)
org.jboss.weld.bean.builtin.CallableMethodHandler.invoke(CallableMethodHandler.java:51)
org.jboss.weld.bean.proxy.EnterpriseTargetBeanInstance.invoke(EnterpriseTargetBeanInstance.java:56)
org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:105)
org.jboss.weldx.persistence.EntityManager$-1570536921$Proxy$_$$_Weld$Proxy$.getTransaction(EntityManager$-1570536921$Proxy$_$$_Weld$Proxy$.java)
de.demoapp.controller.UserController.setLocked(UserController.java:452)
de.demoapp.controller.UserController.lock(UserController.java:721)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
org.apache.el.parser.AstValue.invoke(AstValue.java:262)
org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:39)
org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:50)
com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
javax.faces.component.UICommand.broadcast(UICommand.java:315)
javax.faces.component.UIData.broadcast(UIData.java:1093)
javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:62)
I have also read this article - but it doesn't really help, it still throws: javax.persistence.TransactionRequiredException: no transaction is in progress
I'm not sure if I do something essential wrong...

Yes, there is something essential wrong. You have mismatch between container managed transactions and user managed transactions. Documentation for EntityManager.getTransaction tells quite clearly what is the problem:
Throws:
IllegalStateException - if invoked on a JTA entity manager
Problem comes from entityManager.getTransaction() in your code, hacking with /flush/persist/etc does not matter because exception occurs before those lines are executed.
More details about the subject can be found from: http://en.wikibooks.org/wiki/Java_Persistence/Transactions

okay, because of the the real good answer of Mikko, i do it know right:
I import:
import javax.ejb.TransactionAttribute;
import static javax.ejb.TransactionAttributeType.REQUIRED; // this one is important!!!
my Annotations are now:
#RequestScoped
#Stateful
#TransactionAttribute(value=REQUIRED)
public class UserProvider {
public void setLocked(Long id, boolean locked) {
User user = new User();
user = findUserByID(id);
user.setLocked(locked);
entityManager.merge(user);
}
}
now it works, but the reason is the 2nd import and the anotation!

Related

Error creating child actor

In an Actor I create a child actor like below
ActorRef sessionEventHandlerActor = getContext().actorOf(Props.create(SessionHandler.class), sessionId);
and this is SessionHandler actor:
public class SessionHandler extends UntypedActor {
public SessionHandler() {
getContext().setReceiveTimeout(Duration.create(1, TimeUnit.MINUTES));
}
#Override
public void onReceive(Object message) throws Exception {
}
}
and I get following error:
Caused by: akka.actor.ActorInitializationException: You cannot create an instance of [actors.SessionHandler] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.
at akka.actor.ActorInitializationException$.apply(Actor.scala:165)
at akka.actor.Actor$class.$init$(Actor.scala:421)
at akka.actor.UntypedActor.<init>(UntypedActor.scala:97)
at org.esi.actors.SessionHandler.<init>(SessionHandler.java:22)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at java.lang.Class.newInstance(Class.java:442)
at akka.util.Reflect$.instantiate(Reflect.scala:45)
at akka.actor.NoArgsReflectConstructor.produce(Props.scala:358)
at akka.actor.Props.newActor(Props.scala:249)
at akka.actor.ActorCell.newActor(ActorCell.scala:552)
at akka.actor.ActorCell.create(ActorCell.scala:578)
I do not see any issue in how I create the actor. Does any one know what the problem can be?
Thank you
I think there's no problem anymore, but I think you need to leave out the the sessionId argument, because create will try to apply it to the constructor.
ActorRef sessionEventHandlerActor = getContext().actorOf(Props.create(SessionHandler.class));
As far as I understood the Java API. I only used it in scala.

How to test Spring Data repositories?

I want a repository (say, UserRepository) created with the help of Spring Data. I am new to spring-data (but not to spring) and I use this tutorial. My choice of technologies for dealing with the database is JPA 2.1 and Hibernate. The problem is that I am clueless as to how to write unit tests for such a repository.
Let's take create() method for instance. As I am working test-first, I am supposed to write a unit test for it - and that's where I bump into three problems:
First, how do I inject a mock of an EntityManager into the non-existing implementation of a UserRepository interface? Spring Data would generate an implementation based on this interface:
public interface UserRepository extends CrudRepository<User, Long> {}
However, I don't know how to force it to use an EntityManager mock and other mocks - if I had written the implementation myself, I would probably have a setter method for EntityManager, allowing me to use my mock for the unit test. (As for actual database connectivity, I have a JpaConfiguration class, annotated with #Configuration and #EnableJpaRepositories, which programmatically defines beans for DataSource, EntityManagerFactory, EntityManager etc. - but repositories should be test-friendly and allow for overriding these things).
Second, should I test for interactions? It is hard for me to figure out what methods of EntityManager and Query are supposed to be called (akin to that verify(entityManager).createNamedQuery(anyString()).getResultList();), since it isn't me who is writing the implementation.
Third, am I supposed to unit-test the Spring-Data-generated methods in the first place? As I know, the third-party library code is not supposed to be unit-tested - only the code the developers write themselves is supposed to be unit-tested. But if that's true, it still brings the first question back to the scene: say, I have a couple of custom methods for my repository, for which I will be writing implementation, how do I inject my mocks of EntityManager and Query into the final, generated repository?
Note: I will be test-driving my repositories using both the integration and the unit tests. For my integration tests I am using an HSQL in-memory database, and I am obviously not using a database for unit tests.
And probably the fourth question, is it correct to test the correct object graph creation and object graph retrieval in the integration tests (say, I have a complex object graph defined with Hibernate)?
Update: today I've continued experimenting with mock injection - I created a static inner class to allow for mock injection.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class UserRepositoryTest {
#Configuration
#EnableJpaRepositories(basePackages = "com.anything.repository")
static class TestConfiguration {
#Bean
public EntityManagerFactory entityManagerFactory() {
return mock(EntityManagerFactory.class);
}
#Bean
public EntityManager entityManager() {
EntityManager entityManagerMock = mock(EntityManager.class);
//when(entityManagerMock.getMetamodel()).thenReturn(mock(Metamodel.class));
when(entityManagerMock.getMetamodel()).thenReturn(mock(MetamodelImpl.class));
return entityManagerMock;
}
#Bean
public PlatformTransactionManager transactionManager() {
return mock(JpaTransactionManager.class);
}
}
#Autowired
private UserRepository userRepository;
#Autowired
private EntityManager entityManager;
#Test
public void shouldSaveUser() {
User user = new UserBuilder().build();
userRepository.save(user);
verify(entityManager.createNamedQuery(anyString()).executeUpdate());
}
}
However, running this test gives me the following stacktrace:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.DefaultTestContext.getApplicationContext(DefaultTestContext.java:101)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:319)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:212)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Error setting property values; nested exception is org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'entityManager' threw exception; nested exception is java.lang.IllegalArgumentException: JPA Metamodel must not be null!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1493)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:684)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:121)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:250)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 28 more
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'entityManager' threw exception; nested exception is java.lang.IllegalArgumentException: JPA Metamodel must not be null!
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:108)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:62)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1489)
... 44 more
tl;dr
To make it short - there's no way to unit test Spring Data JPA repositories reasonably for a simple reason: it's way to cumbersome to mock all the parts of the JPA API we invoke to bootstrap the repositories. Unit tests don't make too much sense here anyway, as you're usually not writing any implementation code yourself (see the below paragraph on custom implementations) so that integration testing is the most reasonable approach.
Details
We do quite a lot of upfront validation and setup to make sure you can only bootstrap an app that has no invalid derived queries etc.
We create and cache CriteriaQuery instances for derived queries to make sure the query methods do not contain any typos. This requires working with the Criteria API as well as the meta.model.
We verify manually defined queries by asking the EntityManager to create a Query instance for those (which effectively triggers query syntax validation).
We inspect the Metamodel for meta-data about the domain types handled to prepare is-new checks etc.
All stuff that you'd probably defer in a hand-written repository which might cause the application to break at runtime (due to invalid queries etc.).
If you think about it, there's no code you write for your repositories, so there's no need to write any unittests. There's simply no need to as you can rely on our test base to catch basic bugs (if you still happen to run into one, feel free to raise a ticket). However, there's definitely need for integration tests to test two aspects of your persistence layer as they are the aspects that related to your domain:
entity mappings
query semantics (syntax is verified on each bootstrap attempt anyway).
Integration tests
This is usually done by using an in-memory database and test cases that bootstrap a Spring ApplicationContext usually through the test context framework (as you already do), pre-populate the database (by inserting object instances through the EntityManager or repo, or via a plain SQL file) and then execute the query methods to verify the outcome of them.
Testing custom implementations
Custom implementation parts of the repository are written in a way that they don't have to know about Spring Data JPA. They are plain Spring beans that get an EntityManager injected. You might of course wanna try to mock the interactions with it but to be honest, unit-testing the JPA has not been a too pleasant experience for us as well as it works with quite a lot of indirections (EntityManager -> CriteriaBuilder, CriteriaQuery etc.) so that you end up with mocks returning mocks and so on.
With Spring Boot + Spring Data it has become quite easy:
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
MyRepository subject;
#Test
public void myTest() throws Exception {
subject.save(new MyEntity());
}
}
The solution by #heez brings up the full context, this only bring up what is needed for JPA+Transaction to work.
Note that the solution above will bring up a in memory test database given that one can be found on the classpath.
This may come a bit too late, but I have written something for this very purpose. My library will mock out the basic crud repository methods for you as well as interpret most of the functionalities of your query methods.
You will have to inject functionalities for your own native queries, but the rest are done for you.
Take a look:
https://github.com/mmnaseri/spring-data-mock
UPDATE
This is now in Maven central and in pretty good shape.
If you're using Spring Boot, you can simply use #SpringBootTest to load in your ApplicationContext (which is what your stacktrace is barking at you about). This allows you to autowire in your spring-data repositories. Be sure to add #RunWith(SpringRunner.class) so the spring-specific annotations are picked up:
#RunWith(SpringRunner.class)
#SpringBootTest
public class OrphanManagementTest {
#Autowired
private UserRepository userRepository;
#Test
public void saveTest() {
User user = new User("Tom");
userRepository.save(user);
Assert.assertNotNull(userRepository.findOne("Tom"));
}
}
You can read more about testing in spring boot in their docs.
In the last version of spring boot 2.1.1.RELEASE, it is simple as :
#RunWith(SpringRunner.class)
#SpringBootTest(classes = SampleApplication.class)
public class CustomerRepositoryIntegrationTest {
#Autowired
CustomerRepository repository;
#Test
public void myTest() throws Exception {
Customer customer = new Customer();
customer.setId(100l);
customer.setFirstName("John");
customer.setLastName("Wick");
repository.save(customer);
List<?> queryResult = repository.findByLastName("Wick");
assertFalse(queryResult.isEmpty());
assertNotNull(queryResult.get(0));
}
}
Complete code:
https://github.com/jrichardsz/spring-boot-templates/blob/master/003-hql-database-with-integration-test/src/test/java/test/CustomerRepositoryIntegrationTest.java
When you really want to write an i-test for a spring data repository you can do it like this:
#RunWith(SpringRunner.class)
#DataJpaTest
#EnableJpaRepositories(basePackageClasses = WebBookingRepository.class)
#EntityScan(basePackageClasses = WebBooking.class)
public class WebBookingRepositoryIntegrationTest {
#Autowired
private WebBookingRepository repository;
#Test
public void testSaveAndFindAll() {
WebBooking webBooking = new WebBooking();
webBooking.setUuid("some uuid");
webBooking.setItems(Arrays.asList(new WebBookingItem()));
repository.save(webBooking);
Iterable<WebBooking> findAll = repository.findAll();
assertThat(findAll).hasSize(1);
webBooking.setId(1L);
assertThat(findAll).containsOnly(webBooking);
}
}
To follow this example you have to use these dependencies:
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.197</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
With JUnit5 and #DataJpaTest test will look like (kotlin code):
#DataJpaTest
#ExtendWith(value = [SpringExtension::class])
class ActivityJpaTest {
#Autowired
lateinit var entityManager: TestEntityManager
#Autowired
lateinit var myEntityRepository: MyEntityRepository
#Test
fun shouldSaveEntity() {
// when
val savedEntity = myEntityRepository.save(MyEntity(1, "test")
// then
Assertions.assertNotNull(entityManager.find(MyEntity::class.java, savedEntity.id))
}
}
You could use TestEntityManager from org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager package in order to validate entity state.
I solved this by using this way -
#RunWith(SpringRunner.class)
#EnableJpaRepositories(basePackages={"com.path.repositories"})
#EntityScan(basePackages={"com.model"})
#TestPropertySource("classpath:application.properties")
#ContextConfiguration(classes = {ApiTestConfig.class,SaveActionsServiceImpl.class})
public class SaveCriticalProcedureTest {
#Autowired
private SaveActionsService saveActionsService;
.......
.......
}
you can use #DataJpaTest annotation that focuses only on JPA components. By default, it scans for #Entity classes and configures Spring Data JPA repositories annotated with #Repository annotation.
By default, tests annotated with #DataJpaTest are transactional and roll back at the end of each test.
//in Junit 5 #RunWith(SpringRunner.class) annotation is not required
#DataJpaTest
public class EmployeeRepoTest {
#Autowired
EmployeeRepo repository;
#Test
public void testRepository()
{
EmployeeEntity employee = new EmployeeEntity();
employee.setFirstName("Anand");
employee.setProject("Max Account");
repository.save(employee);
Assert.assertNotNull(employee.getId());
}
}
Junit 4 Syntax will be along with SpringRunner class.
//Junit 4
#RunWith(SpringRunner.class)
#DataJpaTest
public class DataRepositoryTest{
//
}
springboot 2.4.5
import javax.persistence.EntityManager;
import javax.persistence.ParameterMode;
import javax.persistence.PersistenceContext;
import javax.persistence.StoredProcedureQuery;
#Repository
public class MyRepositoryImpl implements MyRepository {
#Autowired
#PersistenceContext(unitName = "MY_JPA_UNIT")
private EntityManager entityManager;
#Transactional("MY_TRANSACTION_MANAGER")
#Override
public MyEntity getSomething(Long id) {
StoredProcedureQuery query = entityManager.createStoredProcedureQuery(
"MyStoredProcedure", MyEntity.class);
query.registerStoredProcedureParameter("id", Long.class, ParameterMode.IN);
query.setParameter("id", id);
query.execute();
#SuppressWarnings("unchecked")
MyEntity myEntity = (MyEntity) query.getResultList().stream().findFirst().orElse(null);
return myEntity;
}
}
import org.junit.jupiter.api.*;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import javax.persistence.EntityManager;
import javax.persistence.StoredProcedureQuery;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
#RunWith(MockitoJUnitRunner.Silent.class)
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class MyRepositoryTest {
#InjectMocks
MyRepositoryImpl myRepository;
#Mock
private EntityManager entityManager;
#Mock
private StoredProcedureQuery storedProcedureQuery;
#BeforeAll
public void init() {
MockitoAnnotations.openMocks(this);
Mockito.when(entityManager.createStoredProcedureQuery(Mockito.any(), Mockito.any(Class.class)))
.thenReturn(storedProcedureQuery);
}
#AfterAll
public void tearDown() {
// something
}
#Test
void testMethod() throws Exception {
Mockito.when(storedProcedureQuery.getResultList()).thenReturn(List.of(myEntityMock));
MyEntity resultMyEntityList = myRepository.getSomething(1l);
assertThat(resultMyEntityList,
allOf(hasProperty("id", org.hamcrest.Matchers.is("1"))
. . .
);
}
}
In 2021 with a new initalized springboot 2.5.1 project, I'm doing it like:
...
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
#ExtendWith(MockitoExtension.class)
#DataJpaTest
public class SomeTest {
#Autowired
MyRepository repo;
#Test
public void myTest() throws Exception {
repo.save(new MyRepoEntity());
/*...
/ Actual Test. For Example: Will my queries work? ... etc.
/ ...
*/
}
}

PowerMock: how to mock static methods which have the same name in a class?

Today I'm working on a class with two static methods which have same name, different parameter types. When I try to mock one of the methods, I encounter this problem.
This is the class to be mocked:
//RequestUtil.java, I want to mock the second config method
public class RequestUtil {
public static void config(String request, List parameters){}
public static void config(HttpServletRequest request, List parameters){}
}
This is the test class:
//RequestUtilTest.java
#RunWith(PowerMockRunner.class)
#PrepareForTest(RequestUtil.class)
public class RequestUtilTest {
//this test will throw NullPointException
#Test
public void testConfig() throws Exception {
mockStatic(RequestUtil.class);
doNothing().when(RequestUtil.class, "config", any(HttpServletRequest.class), anyList());
}
}
Run this test, and it will throw exceptions:
java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.powermock.reflect.internal.WhiteboxImpl.checkIfParameterTypesAreSame(WhiteboxImpl.java:2432)
at org.powermock.reflect.internal.WhiteboxImpl.getMethods(WhiteboxImpl.java:1934)
at org.powermock.reflect.internal.WhiteboxImpl.getBestMethodCandidate(WhiteboxImpl.java:1025)
at org.powermock.reflect.internal.WhiteboxImpl.findMethodOrThrowException(WhiteboxImpl.java:948)
at org.powermock.reflect.internal.WhiteboxImpl.doInvokeMethod(WhiteboxImpl.java:882)
at org.powermock.reflect.internal.WhiteboxImpl.invokeMethod(WhiteboxImpl.java:859)
at org.powermock.reflect.Whitebox.invokeMethod(Whitebox.java:466)
at org.powermock.api.mockito.internal.expectation.PowerMockitoStubberImpl.when(PowerMockitoStubberImpl.java:106)
...
This exception is caused by:
doNothing().when(RequestUtil.class, "config", any(HttpServletRequest.class), anyList());
However, if I mock the first config method, that means, replace this line with:
doNothing().when(RequestUtil.class, "config", anyString(), anyList());
everything is Ok.
The order of the config methods in the defination of RequestUtil class has nothing to do with this issue. No matter config(HttpServletRequest, List) is the first or second config method of RequestUtil, the mock of config(HttpServletRequest, List) will be failure.
Also, if I modify the HttpServletRequest to another "simpler" type, such as int, this issue disappears.
It seems to be a bug of PowerMock, but I'm not sure. I searched Google and stackoverflow, but there are no post or discuss on this issue. So anyone can help me?
Test frameworks I use:
JUnit: 4.10
PowerMock: 1.5.4
Mockito: 1.9.5
It seems to be a PowerMock bug with overloaded methods.
You could bypass it by looking up the method object using the WhiteBox class, and mocking explicitly this method.
...
import org.powermock.reflect.Whitebox;
//RequestUtilTest.java
#RunWith(PowerMockRunner.class)
#PrepareForTest(RequestUtil.class)
public class RequestUtilTest {
//this test will throw NullPointException
#Test
public void testConfig() throws Exception {
mockStatic(RequestUtil.class);
Method method = Whitebox.getMethod(RequestUtil.class, "config", HttpServletRequest.class, List.class);
doNothing().when(RequestUtil.class, method);
}
}
A similar question have been asked previously on stackoverflow.

How to mock a java class inside a Grails unit test?

I have a java class, which I've added to my resources.groovy like this:
import persistentrep.ReasoningXMLLoader;
// Place your Spring DSL code here
beans = {
reasoningXMLLoader(ReasoningXMLLoader)
}
I then use this class in my GrailsService:
class XMLService
{
def reasoningXMLLoader
def someMethod()
{
reasoningXMLLoader.doSomething()
}
}
Obviously, I want to write a unit test that mocks reasoningXMLLoader and injects it into the service.
I tried using #Mock, MockFor and mockFor and I keep getting org.codehaus.groovy.grails.exceptions.GrailsConfigurationException: Cannot add Domain class [class persistentrep.ReasoningXMLLoader]. It is not a Domain! error :
org.codehaus.groovy.grails.exceptions.GrailsConfigurationException: Cannot add Domain class [class persistentrep.ReasoningXMLLoader]. It is not a Domain!
at org.codehaus.groovy.grails.commons.DefaultGrailsApplication.addArtefact(DefaultGrailsApplication.java:916)
at org.codehaus.groovy.grails.commons.DefaultGrailsApplication.addArtefact(DefaultGrailsApplication.java:615)
at org.codehaus.groovy.grails.commons.GrailsApplication$addArtefact.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:131)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSite.invoke(PogoMetaMethodSite.java:226)
at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:52)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at grails.test.mixin.domain.DomainClassUnitTestMixin.mockDomain(DomainClassUnitTestMixin.groovy:128)
at com.vpundit.www.XMLServiceTests.mockDomain(XMLServiceTests.groovy)
at com.vpundit.www.XMLServiceTests.setUp(XMLServiceTests.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Is there a way to mock this using the Grails built-in mocking framework, or do I need to use something like Mockito?
What is the best way to inject the mock? Is there some Grails magic that can do it for me, or do I just use the exposed property -
service.reasoningXMLLoader = mock?
I finally managed to figure out how to do this. I was getting the exception, because I was trying to use the #Mock() attribute, which apparently cannot be used for what I was trying to do.
The task is actually pretty straight forward after reading the Groovy documentation for mocking with closures and with MockFor. I should have realized earlier that Groovy's documentation is better suited for this type of information that Grails'
So here is how to accomplish what I wanted to do, using closures. It's very neat actually:
void testParseXml() {
String xml = "test string"
def mockReturnObject = {create your object to be returned here}
def loader = [parseString:{ mockReturnObject }] as ReasoningXMLLoader
service.reasoningXMLLoader = loader
def result = service.parseXML(xml)
do assertions here
}
Here is how to do the same with mocks:
void testParseXml() {
String xml = "test string"
def mockReturnObject = {create your object to be returned here}
def loader = new MockFor(ReasoningXMLLoader)
loader.demand.parseString{mockReturnObject}
service.reasoningXMLLoader = loader.proxyInstance()
def result = service.parseXML(xml)
do assertions here
}
I hope this helps someone who is new to Grails and Groovy.

Using #Autowired with JMockit makes the #Autowired object null

I realize that there is another SO question which deals with this exact problem (here). However, it won't work in my case.
I have a maven (web/frontend) project using spring. I've added jmockit to the jvm through the pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<argLine>-javaagent:${settings.localRepository}/mockit/jmockit/0.998/jmockit-0.998.jar</argLine>
<useSystemClassLoader>true</useSystemClassLoader>
<forkMode>always</forkMode>
</configuration>
</plugin>
The SUT (abbreviated) looks like:
#Service
#RequestMapping("/bars")
public class BarsController{
[...]
#Autowired
private FooUtils fooUtils;
[...]
#RequestMapping(value = "/get", method = RequestMethod.POST)
public ModelAndView getBars(){
ModelAndView mav = new ModelAndView();
Session session = fooUtils.getSession();
[...]
Now, I would really like to mock out the FooUtils instance in my test. Following the advice given in this SO question, I tried:
#RunWith(JMockit.class)
public class BarsControllerTest {
#Autowired BarsController unitUnderTest;
#Mocked Session session;
#Before
public void setUp()
{
FooUtils foo = new MockUp <FooUtils>() {
#Mock
Session getSession() {
return session;
}
}.getMockInstance();
mockit.Deencapsulation.setField(unitUnderTest, foo);
}
Alas, the unitUnderTest as well as the foo are both null, causing this to happen:
java.lang.NullPointerException
at net.manniche.thebars.BarsControllerTest.setUp(BarsControllerTest.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:172)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:78)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:70)
Which is quite unexpected, as I would expect new MockUp<...>{}.getMockInstance() to return some object.
I guess that I'm just missing out on some crucial part, but which?