Mockito: NPE when capturing Spring Data saveOrUpdate() argument - spring-data-jpa

I'm trying to unit test a Spring Data repository and to mock its saveOrUpdate() method. The repository is as follows:
#Repository
public interface MyRepository extends CrudRepository<MyEntity, Long> {
...
}
The unit test:
public MyTest {
...
#Mock
private MyRepository myRepository;
#Captor
private ArgumentCaptor<MyEntity> myEntityCaptor;
...
#Test
public void test123() {
Mockito.doNothing().when(myRepository).saveOrUpdate(Mockito.any(MyEntity.class));
MyEntity myEntity = ...;
myRepository.saveOrUpdate(myEntity);
Mockito.verify(myRepository).saveOrUpdate(myEntityCaptor.capture());
assertThat(myEntityCaptor.capture().getId()).isEqualTo(1L);
...
}
Running the unit test raises NPE on the assert as myEntityCaptor.capture() is null. What am I doing wrong ? Why doesn't the capture work in this case ?
Many thanks in advance.
Seymour

Sorry for posting stupid things here, I just corrected the line:
assertThat(myEntityCaptor.capture().getId()).isEqualTo(1L);
to read:
assertThat(myEntityCaptor.getValue().getId()).isEqualTo(1L);

Related

Mockito fails for Spring data JPA Page interface

#SpringBootTest
public class TestClass {
#Mock
private Page<Customer> pagedResult;
#Mock
private Pageable paging = PageRequest.of(0, 1);
#Mock
private CustomerRepository cutomerRepository;
#InjectMocks
private CustomerServiceImpl service;
#Test
void testss() {
Set<Integer> set = new HashSet<>();
set.add(1);
Pageable paging1 = PageRequest.of(0, 1);
Page<Customer> pa = new PageImpl<>(Arrays.asList(customer));
when(cutomerRepository.findByIdIn(set, paging1)).thenReturn(pa);
when(service.test(set)).thenReturn(Arrays.asList(customer));
assertEquals(customer.getName(), service.test(set).get(0).getgetName());
}
}
Implementation class
public class CustomerServiceImpl {
private CustomerRepository customerRepository ;
public CustomerServiceImpl(CustomerRepository customerRepository ) {
super();
this.customerRepository = customerRepository ;
}
#Override
public List<Customer> test(Set<Integer> ids) {
Pageable paging = PageRequest.of(0, 1);
Page<Customer> pagedResult = customerRepository.findByIdIn(ids, paging);
return pagedResult.toList();
}
}
I am trying to write the Junit test case for my pagination code using mockito but it fails as it is expecting the return type for method as Page.but I am returning List of Customers.When I return Page from method it works fine but if I return List is fails with below mentioned error
I am getting below error
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
ArrayList cannot be returned by findByIdIn()
findByIdIn() should return Page
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
This exception might occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
I think something is messed with your code.
In Your code you have doctorRepository.findByIdIn Method bt in your test class it is cutomerRepository.findByIdIn.
I have added the below code as a reference with respect to your CustomerServiceImpl.
You can try the same way to execute your test.
SpringBootTest
public class TestClass {
#Mock
private Pageable paging;
#Mock
private CustomerRepository cutomerRepository;
#Mock
private DoctorRepository doctorRepository;
#InjectMocks
private CustomerServiceImpl service;
#Test
void testss() {
Doctor doctor = new Doctor();
doctor.setName("test name");
Set<Integer> set = new HashSet<>();
set.add(1);
PageImpl<Doctor> page = new PageImpl<>(Arrays.asList(doctor));
when(doctorRepository.findByIdIn(Mockito.any(), Mockito.any())).thenReturn(page);
List<Doctor> doctors= service.test(set);
assertEquals(doctor.getName(), doctors.get(0).getgetName());
}
}

Integration Tests for RESTEasy Endpoint

I want to perform integration tests on my REST endpoint but am running into issues.
Below is my endpoint. NOTE: I cannot change this part of the code.
#Path("/people")
public class PersonResource {
private final PersonService personService;
#Inject
public PersonResource(final PersonService personService) {
this.personService = personService;
}
#GET
#Produces("application/json")
public List<Person> getPersonList() {
return personService.getPersonList();
}
}
From what I've been able to find online, I have the following basic structure for my test.
public class PersonResourceTest {
private Dispatcher dispatcher;
private POJOResourceFactory factory;
#Before
public void setup() {
dispatcher = MockDispatcherFactory.createDispatcher();
factory = new POJOResourceFactory(PersonResource.class);
dispatcher.getRegistry().addResourceFactory(factory);
}
#Test
public void testEndpoint() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("people");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
System.out.print("\n\n\n\n\n" + response.getStatus() + "\n\n\n\n\n");
System.out.print("\n\n\n\n\n" + response.getContentAsString() + "\n\n\n\n\n");
}
}
However, this results in the following error on the last line of the setup method.
java.lang.RuntimeException: RESTEASY003190: Could not find constructor for class: my.path.PersonResource
I explored the Registry API and thought maybe I should have been using addSingletonResource instead, so I changed the last line of setup to dispatcher.getRegistry().addSingletonResource(personResource); and added the following.
#Inject
private PersonResource personResource;
But that results in a NullPointerException on the last line of setup.
The sparse documentation on the mocking isn't very helpful. Can anyone point out where I'm going wrong? Thanks.
You need to do two things
Add a no arguments constructor to your source class:
public PersonResource() {
this(null)
}
In the test class, initialize the PersonResource class with an instance of PersonService class:
dispatcher.getRegistry().addSingletonResource(new PersonResource(new PersonService()));
If needed, the PersonService class can be mocked:
private Dispatcher dispatcher;
#Mock
private PersonService service;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
dispatcher = MockDispatcherFactory.createDispatcher();
PersonResource resource= new PersonResource(service);
ispatcher.getRegistry().addSingletonResource(resource);
}
Hope it helps!

Mockito with transactional annotated method

We've got a class with a method with an transactional annotation
public class MyHandler extends BaseHandler {
#Transactional
public void annotatedMethod(String parameter) throws Exception {
}
As soon as we try to make a test using mockito and its annotations
#InjectMocks
private Controller controller;
#Mock
private MyHandler myHandler;
we have a null pointer exception when executing the following line
Mockito.doCallRealMethod().when(myHandler).annotatedMethod(Matchers.any());
We have tried to use the same solution as in Transactional annotation avoids services being mocked with no luck.
We're new with mockito, we have no idea how to solve this.
Any clues?
Thank you very much,
Elena
you can try this way to mock the data. I have the similar NullPointerException and this way helped me.
#InjectMocks
private Controller controller;
#Mock
private MyHandler myHandler;
#Test
void testingMethod() {
when(myHandler.annotatedMethod(Mockito.any())).thenReturn("something");
}

Implementing Projection with Specification in Spring Data JPA

I am trying to implement the projection with specification in Spring Data JPA via this implementation:
https://github.com/pramoth/specification-with-projection
Related classes are as follows:
Spec:
public class TopicSpec {
public static Specification<Topic> idEq(String id){
return (root, query, cb) -> cb.equal(root.get(Topic_.id),id);
}
}
Repository
#Repository
public interface TopicRepository extends JpaRepository<Topic,String>,JpaSpecificationExecutorWithProjection<Topic> {
public static interface TopicSimple{
String getId();
String getName();
}
List<TopicSimple> findById(String id);
}
Test
#Test
public void specificationWithProjection() {
Specification<Topic> where= Specifications.where(TopicSpec.idEq("Bir"));
List<Topic> all = topicRepository.findAll(where);
Assertions.assertThat(all).isNotEmpty();
}
I have this response from the Get method:
However the tests fail. Besides when I pull the github project of pramoth I can run the tests with success. Does anyone have any opinion about this issue?
The full project can be found here:
https://github.com/dengizik/projectionDemo
I have asked the same question to the developer of the project Pramoth Suwanpech, who was kind enough to check my code and give answer. My test class should've implement the test object like this:
#Before
public void init() {
Topic topic = new Topic();
topic.setId("İki");
topic.setName("Hello");
topicRepository.save(topic); }
With this setting the tests passed.

Junit 4 + Eclipse - Run inner class test cases with SpringJUnit4ClassRunner as well

I need to run inner class test cases from eclipse using Junit4. I understand that there is org.junit.runners.Enclosed that is intended to serve this purpose. It works well for "plain" unit test i.e. without the need for spring context configuration.
For my case, give sample code below, Adding another annotation of Enclosed does not work since there is a conflict of both SpringJUnit4ClassRunner and Enclosed test runners. How can I solve this problem ?
Note: Kindly ignore any basic spelling mistake/basic import issues in the below example since I tried to cook up from my actual use-case.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/unit-test-context.xml"})
public class FooUnitTest {
// Mocked dependency through spring context
#Inject
protected DependentService dependentService;
public static class FooBasicScenarios extends FooUnitTest{
#Test
public void testCase1 {
.....
List<Data> data = dependentService.getData();
.....
}
}
public static class FooNeagativeScenarios extends FooUnitTest{
#Test
public void testCase1 {
.....
List<Data> data = dependentService.getData();
.....
}
}
}
}
FooUnitTest is a container, you cannot use it as a superclass.
You need to move all your spring-code to Scenario-classes. And use #RunWith(Enclosed.class). For example, with abstract superclass
#RunWith(Enclosed.class)
public class FooUnitTest {
#ContextConfiguration(locations = { "/unit-test-context.xml"})
protected abstract static class BasicTestSuit {
// Mocked dependency through spring context
#Inject
protected DependentService dependentService;
}
#RunWith(SpringJUnit4ClassRunner.class)
public static class FooBasicScenarios extends BasicTestSuit {
#Test
public void testCase1 {
.....
List<Data> data = dependentService.getData();
.....
}
}
#RunWith(SpringJUnit4ClassRunner.class)
public static class FooNeagativeScenarios extends BasicTestSuit {
#Test
public void testCase1 {
.....
List<Data> data = dependentService.getData();
.....
}
}
}
Of course you can declare all dependencies in each Scenario-class, in that case there is no necessary in abstract superclass.