Unable to unit test a spring service calling mocked custom repository - unit-testing

I defined a custom repository Interface which get stream of entities through Query.getResultStream
public interface MyRepository<T> {
Stream<T> findByCriteria(...);
}
public class MyRepositoryImpl<T> implements MyRepository<T> {
#Autowired SessionFactory sessionFactory;
public Stream<T> findByCriteria(...) {
...
}
}
and my Repository & Service
#Repository
public interface EntityRepository extends MyRepository<Entity> {
...
}
#Service
#Transactional(readOnly = true)
public class EntityService {
#Autowired EntityRepository entityRepository;
public Stream<Entity> getEntitiesByCriteria(String criteria) {
...
return entityRepository.findByCriteria(...);
}
}
Problem is my Service Unit Test does not see the repository implementation, and always return null without going inside findByCriteria implementation.
ExtendWith(MockitoExtension.class)
class EntityServiceTest {
#InjectMocks EntityService service;
#Mock EntityRepository repository;
#Test
void test() {
...
when(repository.findByCriteria(...))
.thenReturn(...);
service.getEntitiesByCriteria(...); //This does not see the implementation of findByCriteria in MyRepositoryImpl
]
}
I tried many annotations like #RepositoryDefinition in my interface or #EnableJpaRepositories in my test class but nothing seems to work

Related

Unit Testing Service Layer in Spring Boot

I have a service layer (Code Below:)
#Service
public class EquityFeedsService {
#Autowired
private EquityFeedsRedisRepositoryImpl equityFeedsRedisRepositoryImpl;
public void save(EquityFeeds equityFeeds) {
logger.info("Inside the save method of EquityFeedsService.");
equityFeedsRedisRepositoryImpl.save(equityFeeds);
}
// other methods
}
Now I am trying to write a Unit Test case for the above method below:
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
public class EquityFeedsServiceTest {
private MockMvc mockMvc;
#InjectMocks
private EquityFeedsService equityFeedsService;
#Mock
private EquityFeedsRedisRepositoryImpl equityFeedsRedisRepositoryImpl;
#BeforeEach
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(equityFeedsService).build();
}
#Test
public void testSaveMethod() {
EquityFeeds equityFeeds = new EquityFeeds(423,"SAPEXTXN1", "GS");
when(equityFeedsRedisRepositoryImpl.save(any(EquityFeeds.class))).thenReturn(new EquityFeeds());
}
}
This code gives me the below Exception:
in line (any(EquityFeeds.class))
Required type:
EquityFeeds (This is my model class)
Provided:
Matcher <com.investmentbank.equityfeedsprocessingupdated.model.EquityFeeds> (This is the fully qualified path name of the mode class)
no instance(s) of type variable(s) T exist so that Matcher<T> conforms to EquityFeeds
and Exception :
Cannot resolve method 'thenReturn(com.investmentbank.equityfeedsprocessingupdated.model.EquityFeeds)'
What is wrong with my Unit Test Case? How do i solve this?

Mock object is not being returned

There is a Adapter class which calls another legacyService and legacyService calls legacyDao and I want to mock the Legacy service calls.
In the below code SomeBean is returned as null instead of one the one that i created and passed in thenReturn. What could be the issue here?Please help I am new to mocking framework.
public class AdapterImpl implements Adpater{
//Injected through setter or constructor injection
private LegacyService legacy;
public SomeBean myMethod(){
CommonUtils.someStaticMethod()
return legacy.legacyService();
}
}
public class LegacyServiceImpl implements LegacyService{
//Injected through setter or constructor injection
private LegacyDAO ldao;//LegacyDAO is an interface
public SomeBean legacyService(){
return ldao.legacyDAO();
}
}
Test class
#RunWith(PowerMockRunner.class)
#PrepareForTest({CommonUtils.class})
public class AdapterImplTest{
#Mock private LegacyServiceImpl legacyService;
private LegacyDAO legacyDAO;
#Before
public void before(){
MockitoAnnotations.initMocks(this);
}
#Test
public void myMethodTest(){
PowerMockito.mockStatic(CommonUtils.class);
PowerMockito.when(CommonUtils.someStaticMethod()).thenReturn(someString());
legacyDAO = PowerMockito.mock(LegacyDAO.class);
SomeBean bean = new SomeBean(sometring1,somestring2);
PowerMockito.when(legacyDAO.legacyDAO().thenReturn(bean);//I am mocking interface method implementation
legacyService.setLegacyDAO(legacyDAO);
PowerMockito.when(legacyService.legacyService().thenReturn(bean);//same bean as above
AdapterImpl impl = new AdapterImpl();
impl.setLegacyService(legacyService)
//Below method call is not returning the bean that I constructed above it is being returned as null
impl.myMethod();
}
}
The original code posted in the question has many typos like missing parentheses and semi-colons. When I correct them, and fill in some of the methods like AdapterImpl.setLegacyService(), the test passes.
Then, as suggested in my comment, I removed the mocking of LegacyDAO. That mock object should not be needed if LegacyServiceImpl.legacyService() is properly mocked. When I rerun the test, it again passes.
All of which leads me to believe that there is an issue with the injection of the mock LegacyService object into AdapterImpl
FYI here is my passing test code, showing my typo fixes and assumptions about methods not shown in the original question. Hope this helps!
#RunWith(PowerMockRunner.class)
#PrepareForTest({ AdapterImplTest.CommonUtils.class })
public class AdapterImplTest {
#Mock
private LegacyServiceImpl legacyService;
// private LegacyDAO legacyDAO; // removed, no need to mock
#Before
public void before() {
MockitoAnnotations.initMocks(this);
}
#Test
public void myMethodTest() {
PowerMockito.mockStatic(CommonUtils.class);
PowerMockito.when(CommonUtils.someStaticMethod()).thenReturn(someString());
// legacyDAO = PowerMockito.mock(LegacyDAO.class);
SomeBean bean = new SomeBean("sometring1", "somestring2");
// I am mocking interface method implementation
// PowerMockito.when(legacyDAO.legacyDAO()).thenReturn(bean);
// legacyService.setLegacyDAO(legacyDAO);
// same bean as above
PowerMockito.when(legacyService.legacyService()).thenReturn(bean);
AdapterImpl impl = new AdapterImpl();
impl.setLegacyService(legacyService);
// Below method call is not returning the bean that I constructed above
// it is being returned as null
impl.myMethod();
}
private String someString() {
return "hello";
}
public class SomeBean {
public SomeBean(String string, String string2) {
}
}
public interface LegacyService {
public SomeBean legacyService();
}
public interface Adpater {
}
public class AdapterImpl implements Adpater {
// Injected through setter or constructor injection
private LegacyService legacy;
public SomeBean myMethod() {
CommonUtils.someStaticMethod();
return legacy.legacyService();
}
public void setLegacyService(LegacyServiceImpl legacyService) {
legacy = legacyService;
}
}
public class LegacyServiceImpl implements LegacyService {
// Injected through setter or constructor injection
private LegacyDAO ldao;// LegacyDAO is an interface
public SomeBean legacyService() {
return ldao.legacyDAO();
}
public void setLegacyDAO(LegacyDAO legacyDAO) {
ldao = legacyDAO;
}
}
public class LegacyDAO {
public SomeBean legacyDAO() {
return null;
}
}
public static class CommonUtils {
public static String someStaticMethod() {
return "in CommonUtils.someStaticMethod()";
}
}
}

Unit testing callback based on Consumer functional interface

I'm trying to unit test code that runs as callback in a Consumer functional interface.
#Component
class SomeClass {
#Autowired
private SomeInteface toBeMockedDependency;
public method() {
toBeMockedDependency.doSomething(message -> {
// Logic under test goes here
// (implements java.util.function.Consumer interface)
...
});
}
}
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#InjectMocks
private SomeClass someClass;
#Mock
private SomeInteface toBeMockedDependency;
#Test
public void testMethod() {
...
someClass.method();
...
}
}
Essentially I want to provide the tested code some tested "message" via "toBeMockedDependency".
How can the "toBeMockedDependency" be mocked to provide a predefined message?
Is it the right approach?
Don't try to make toBeMockedDependency automatically call your functional interface. Instead, use a #Captor to capture the anonymous functional interface, and then use your test to manually call it.
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#InjectMocks
private SomeClass someClass;
#Mock
private SomeInteface toBeMockedDependency;
#Captor
private ArgumentCaptor<Consumer<Message>> messageConsumerCaptor;
#Test
public void testMethod() {
someClass.method();
verify(toBeMockedDependency).doSomething(messageConsumerCaptor.capture());
Consumer<Message> messageConsumer = messageConsumerCaptor.getValue();
// Now you have your message consumer, so you can test it all you want.
messageConsumer.accept(new Message(...));
assertEquals(...);
}
}

#InjectMocks isnt actually injecting mocks

So i have a class that needs to be tested. Lets call it ClassToTest. It has a couple of Dao objects as fields.
Public class ClassToTest {
#Autowired
MyDao dao;
void methodToTest() {
dao.save(something);
}
}
As you can see ClassToTest does not contain any constructor or setter and I am using spring to autowire the fields.
Now, I have a base test class with all the dependencies that classToTest requires:
public abstract BaseTest {
#Mock
MyDao dao;
}
And the testClass extends this BaseTest class :
public class TestClass extends BaseTest {
#InjectMocks
ClassToTest classToTest = new ClassToTest();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() {
classToTest.methodToTest();
}
}
This results in a null pointer exception when the save happens. However, if i change setup method to this :
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
classToTest.dao = dao;
}
the test passes.
My understanding was that when a class does not have a constructor or a setter, InjectMocks would inject the mocks by using field injection. Why is that not happening here?
Figured out that this is a bug in the 1.8.5 version that i was using : https://code.google.com/p/mockito/issues/detail?id=229.
Upgrading 1.10 fixed the issue.

How can I test RESTful methods with Arquillian?

I have a set of classes to work with REST methods in project. They look like this:
#Path("customer/")
#RequestScoped
public class CustomerCollectionResource {
#EJB
private AppManager manager; // working with DB
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response list(#QueryParam("email") String email) {
final List<Customer> entities = manager.listCustomers(email);
// adding customers to result
return Response.ok(result).build();
}
}
After that I've wrote test method:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test #GET #Path("projectName/customer") #Consumes(MediaType.APPLICATION_JSON)
public void test(ClientResponse<List<Customer>> response) throws Exception {
assertEquals(Status.OK.getStatusCode(), response.getStatus());
}
}
And I get NullPointerException when trying to run this test. It's because of empty response in test case. Why is this happens? DB is configured properly.
There are two modes an arquillian test can run: in-container and client mode. HTTP interfaces can be tested only in client mode (never tried the extensions, only used vanilla Arquillian for this).
By default the test methods executed in the context of the container, called by the arquillian test runner servlet.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean; // EJBs can be injected, also CDI beans,
// PersistenceContext, etc
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
#Test
public void some_test() {
bean.checkSomething();
}
}
In client mode, the test methods are running outside of the container, so you don't have access to EJBs, EntityManager, etc injected into the test class, but you can inject an URL parameter for the test method.
#RunWith(Arquillian.class)
public class CustomerResourceTest {
// testable = false here means all the tests are running outside of the container
#Deployment(testable = false)
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
// Adding omitted
//.addClasses(....)
}
// baseURI is the applications baseURI.
#Test
public void create_account_validation_test (#ArquillianResource URL baseURI) {
}
You can use this URL parameter to build URLs to call your HTTP service using whatever method you have, like the new JAX-RS client API.
You can also mix the two modes:
#RunWith(Arquillian.class)
public class CustomerResourceTest {
#EJB SomeBean bean;
#Deployment
public static WebArchive createTestArchive() {
return ShrinkWrap.create(WebArchive.class, "test.war")
}
#Test
#InSequence(0)
public void some_test() {
bean.checkSomething();
}
#Test
#RunAsClient // <-- this makes the test method run in client mode
#InSequence(1)
public void test_from_client_side() {
}
}
This is sometimes even necessary, because some extensions, like persistence cannot run in client mode.