• Rewriting the note for this because my other notes about unit testing are a MESS rn

Quickstart (basics)

@ExtendWith(MockitoExtension.class)
public class ProductServiceTest {
	@Mock
	ProductRepository productRepository;
 
	@InjectMocks
	ProductService productService;
	
	@Test
	void addProductShouldAddProductSuccessfully() {
		// given
		Product product = new Product();
		product.setId(1);
		product.setName("Book");
		Mockito.when(productRepository.save()).thenReturn(product);
		
		// when
		Product addedProduct = productService.addProduct(product);
		
		// then
		Assertions.assertNotNull(addedProduct);
		Assertions.assertEquals(product.getId(), addedProduct.getId());
		Assertions.assertEquals(product.getName(), addedProduct.getName());
		Assertions.assertTrue(product.getId()==1);
	}
	
	@Test
	public void deleteProductShouldDeleteSuccessfully() {
		// given
		doNothing().when(productRepository).deleteById(1);
	
		// when
		productService.deleteProduct(1);
		
		// then
		Mockito.verify(productRepository, times(1)).deleteById(1);
	}	
}
  • addProductShouldAddProductSuccessfully
    • InjectMocks
      • injects the necessary mocks, for example the productService needs a ProductRepository
    • Because the productRepository is a mock, when we save something using the service it will return null
      • So we basically have to mock the save method that’s called in the service
      • We do that using Mockito’s .when
        • if method returns: when + .thenReturn
        • if method doesn’t return: doNothing().when
    • Now we make the assertions
      • assertNotNull()
      • assertEquals()
      • assertTrue
      • You can just import org.junit.jupiter.api.Assertions too lol
  • deleteProductShouldDeleteSuccessfully
    • doNothing().when(productRepository).deleteById(1);
    • Mockito.verify
      • different verification methods: times(n), never(), atLeastOnce() etc (you can see in intellij)

Testing private methods

	// testing private methods
@Test
void testPrivateMethod_validateProductName() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
	Method validateProductName = ProductService.class.getDeclaredMethod("validateProductName", String.class);
	validateProductName.setAccessible(true); // provided by java reflection
	
	Boolean book = (Boolean) validateProductName.invoke(productService, "Book");
	
	assertTrue(book); // for invalidation, you can use assertFalse(book)
}
  • void testPrivateMethod_validateProductName() - testing private methods
    • Use Java Reflections!
    • Just adds the exceptions of whatever it wants lol

Testing exceptional scenarios

@Test
void addProductShouldThrowExceptionForInvalidProductName() {
	// given
	Product product = new Product();
	product.setId(1);
	product.setName("");
	
	// when
	Product addedProduct = productService.addProduct(product);
	
	// then
	assertThrows(RuntimeException.class, () -> {
		productService.addProduct(product);
	})
	assertEquals("Invalid Name Of Product", runtimeException.getMessage());
	verify(productRepository, times(0)).save(any(Product.class));
}