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
}
}
Related
I'm using spring boot rest API and want to test my service layer. In my service I have autowired few beans and its not through constructor. (I like it that way to keep it short).
In the junit, I have created mocks and for private field which I do want to execute, I have assigned using ReflectionTestUtils.setField. When I debug, the method inside the field is not getting executed which assigned by bean.
Service Class
#Component
public class MyService {
#Autowired
private MyRepository myRepository;
#Autowired
private ResponseMapper responseMapper;
public List<MyObj> getList(String param) throws MyException {
log.info("Getting details");
Optional<List<MyObj>> list = myRepository.findByParam(param);
List<MyObj> data = responseMapper.mapToResponseData(list);
return data;
}
}
Test Class
#RunWith(MockitoJUnitRunner.class)
public class MyServiceTest {
#InjectMocks
private MyService myService;
#Mock
private MyRepository myRepository;
#Mock
private ResponseMapper responseMapper;
#Before
public void setUp() {
ReflectionTestUtils.setField(myService, "responseMapper", responseMapper);
}
#Test
public void getListTest() throws Exception {
when(myRepository.findByParam(anyString()))
.thenReturn(Optional.of(getSampleList()));
List<MyObj> list = myService.getList("param");
assertTrue(list.size() >0);
}
}
This results in Assertion failure and when I debug, the method mapToResponseData in ResponseMapper is not getting executed.
I know I can mock mapToResponseData method also. But I wanted it to execute so I don't have to write another test class for mapper alone.
What am I doing wrong? Is this the right wat to inject bean? And is using constructor in service to inject beans only option?
I have a Service A which autowired Service B and is using a method from Service B.
Service B autowired another Service C and is using a method from it.
I am writing a test for Service A and the test fails at the call where Service B is invoked.At this point Service C is null.
I have tried #Mock for Service B. Nothing seems to work. How can i successfully test this service which is failing on a service that it isnt explicitly autowiring.
//Service A
#Service
public class FileServiceImpl{
#Autowired
private FileNameServiceImpl fileNameService;
public void createFile(String fileName){
String targetFileName = fileNameService.getTargetFileName(fileName);
}
}
//Service B
#Service
public class FileNameServiceImpl{
#Autowired
private CustomDateService customDateService
public String getTargetFileName(String fileName){
return fileName + customDateService.getCustomDate();
}
}
//CustomDate - this is an interace. The Impl is in another package.
public interfaceCustomDateService{
public String getCustomDate();
}
I am trying to test FileServiceImpl , however it fails with a NullPointer Exception because customDateService is null.
Even though, FileServiceImpl is not calling customDateService.
This is what I have for test thus far:
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class FileServiceImplTest {
#Spy
#InjectMocks
private FileServiceImpl fileServiceImpl;
#Mock
private FileNameServiceImpl fileNameService;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testFileName() {
String fileName = "test1.txt";
fileServiceImpl.createFile(fileName); // Test Fails here
Mockito.validateMockitoUsage();
}
As Shane eluded, this sounds like you're maybe integration testing.
If so, make sure the context of your test encompasses the autowired components.
You should post some code, as it's hard to know what exactly is going on here.
If you aren't integration testing, don't rely on autowiring, just construct new ServiceA manually passing in a mocked ServiceB.
Also make sure to initialise your mocks.
private ServiceA serviceA;
#Mock
private ServiceB serviceB;
#BeforeEach
public void setUp() {
MockitoAnnotations.initMocks();
serviceA = new ServiceA(serviceB);
}
EDIT:
First of all, as good practice you should favor constructor injection over field injection in Spring.
So set up the service classes with Autowired constructors.
Also, I'm pretty sure with a mockito Spy you have to initialise the class.
If you switch to use constructor Autowiring you can inject the mocks manually.
#Category(UnitTest.class)
#RunWith(MockitoJUnitRunner.class)
public class FileServiceImplTest {
#Spy
private FileServiceImpl fileServiceImpl;
#Mock
private FileNameServiceImpl fileNameService;
#Before
public void init() throws Exception {
MockitoAnnotations.initMocks(this);
fileServiceImpl = new FileServiceImpl(fileNameService);
}
#Test
public void testFileName() {
String fileName = "test1.txt";
fileServiceImpl.createFile(fileName); <-- now this shouldn't fail
Mockito.validateMockitoUsage();
}
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.
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");
}
}
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