How to write JUnit test cases with ignoring database activities

Viewed 1745

The following is my test class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/ds-context.xml")
@WebAppConfiguration
public class PaidListTest {

    @Autowired
    PaymentService paymentService;

    @Test
    public void getPaidList() {
        List<PaymentGetServiceDO> response = null;
        try {
            response = paymentService.setPaidStatusList();          
            if(response != null && response.size() > 0){
                for(int i = 0; i < response.size(); i++){
                    assertNotNull(response.get(i).getAgentcode());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

In the DAO layer of the service call paymentService.setPaidStatusList() have some operations with database activities of save and update, like em.merge(renewalPoliciesDO);
But I don't want to execute them while calling the test method, they needs to get called only when actual business logic is called.
How can I restrict or rollback the database transactions here?
The service and DAO methods are tedious here. However, I have simplified them for your reference.
Service method if(!updateList.isEmpty()){ HashMap<String,String> recordset = new HashMap<String,String>(); recordset = paymentDAO.setRenewalStatus(updateList); }
DAO implementation

if(paymentUpdateResDO.getPaymentstatus().equalsIgnoreCase("MANUAL") && 
!responseUpdateStatus.getPolicystatusid().equals(renewedStatusId)){
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Integer> payQuery = criteriaBuilder.createQuery(Integer.class);
Root<PaymentStatusDO> payRoot = payQuery.from(PaymentStatusDO.class);
payQuery.multiselect(payRoot.get("paymentstatusid"));
payQuery.where(criteriaBuilder.equal(payRoot.get("paymentstatusdescription"), "Manual"));
Integer paymentStatusId = em.createQuery(payQuery).getSingleResult();
insertOldPolicy(responseUpdateStatus);
responseUpdateStatus.setNewpolicyno(paymentUpdateResDO.getNewpolicyno());
responseUpdateStatus.setPreviousstatusid(responseUpdateStatus.getPolicystatusid());
responseUpdateStatus.setPolicystatusid(renewedStatusId);
Timestamp modifiedDate = new Timestamp(System.currentTimeMillis());
responseUpdateStatus.setModifieddatetime(modifiedDate);
responseUpdateStatus.setModifiedby("RPA");
responseUpdateStatus.setPaymentstatusid(paymentStatusId);
responseUpdateStatus.setActiveindicator("Y");
em.merge(responseUpdateStatus);
successRecords++;
}

In my case, I need the result arraylists, but the em.merge and em.persist activities need to be ignored.

When I try with MockitoJUnitRunner as @GauravRai1512 preferred, I get my testcase executed but the program is terminated so that I am unable to get the result ArrayLists.

Screenshot for successful execution of testcase
Refer this image Program terminated, so that nothing got executed

3 Answers

You should follow below approach as suggested by Pooja Aggarwal.

import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;

    @RunWith(MockitoJUnitRunner.class)
    public class PaidListTest {

        @Mock
        PaymentService paymentService;

        @Before
          public void setUp() {
             MockitoAnnotations.initMocks(this);
             mapperObj = new ObjectMapper();
             List<PaymentGetServiceDO> response = new ArrayList<PaymentGetServiceDO>();
}
        @Test
        public void getPaidList() {
            List<PaymentGetServiceDO> response = null;
            try {
                response = paymentService.setPaidStatusList();          
                if(response != null && response.size() > 0){
                    for(int i = 0; i < response.size(); i++){
                        assertNotNull(response.get(i).getAgentcode());
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

This code will not execute your save and update operation.

Like others have said, you can either:

  • Mock the PaymentService so that you can define exactly what to do on each of the calls to it. In this case, you would simply return a hard-coded List<PaymentGetServiceDO> response, and your test could do something with that. The downside of this is that you're not really testing PaymentService in that case. You're simply looking at hard-coded data, and doing something with it. In my view, that's not a valid test.

  • Or, you can instantiate a PaymentService object with either an in-memory database, only for use with tests, or with a mock DB object, where you can then define exactly how to respond to each of the merge, save, update and similar operations. If the PaymentService object doesn't allow this, then it should be redesigned so it accepts as a parameter a Database/Connection, which would be the normal @Autowired injected parameter when running in production, but which you can instantiate manually when testing. This would be a proper test, since you'd be validating the rest of the logic inside setPaidStatusList, but you're not actually hitting a database to achieve that.

Related