Test Spring-Boot Repository interface methods without touching the database using Mockito

12,648

Solution 1

"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.

Solution 2

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

Share:
12,648
Deniss M.
Author by

Deniss M.

I'm just a newb trying to get it together. It is quite hard to do it in a sense that I needs some time to do it.

Updated on July 06, 2022

Comments

  • Deniss M.
    Deniss M. over 1 year

    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?

  • Johon smuthio
    Johon smuthio over 1 year
    why we need to use @ injectMock instead of @ Autowired with TransactionService ?
  • Johon smuthio
    Johon smuthio over 1 year
    I have got the answer, and the answer is that you need to inject the mocks needed for repo class so for that you have to use @injectMocks with repo class.