JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
JUnit platform is the core, foundational module of JUnit 5. JUnit Jupiter module is for writing tests and extensions. And JUnit Vintage module is for running JUnit 3 and JUnit 4 tests.Although JUnit 5 is a breakthrough change, writing tests with JUnit 5 is still very similar to JUnit 4 so programmers can quickly use JUnit 5 if they were familiar with previous versions of JUnit.For complete details about JUnit 5 features, I recommend you to look at the official JUnit 5 user guide.
For purpose
| JUnit 5 | JUnit 4 |
Declare a test method
|
@Test |
@Test |
Execute before all test methods |
@BeforeAll |
@BeforeClass
|
Execute before each test method |
@BeforeEach |
@Before
|
Execute after each test method |
@AfterEach |
@After
|
Execute after all test methods |
@AfterAll |
@AfterClass
|
Skip a test method/class |
@Disabled |
@Ignore
|
Tagging and filtering tests |
@Tag |
@Category
|
Run with an extension |
@RunWith |
@ExtendWith
|
import static org.junit.jupiter.api.Assertions.fail; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class StandardTests { @BeforeAll static void initAll() { // initializes resources before all test methods } @BeforeEach void init() { // initializes resources before each test method } @Test void successTest() { // this test will pass } @Test void failTest() { fail("this test will fail"); } @Test @Disabled void skippedTest() { // this test is skipped temporarily } @AfterEach void tearDown() { // releases resources after each test method } @AfterAll static void tearDownAll() { // releases resources after all test methods } }JUnit 5 changes the annotation names for better reflecting their meanings, and the behavior is the same as JUnit 4.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.4.4.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.6.2</version> </dependency>As you can see, the last dependency is for JUnit Jupiter which includes modules for JUnit platform and JUnit Jupiter engine.
package net.codejava; import javax.persistence.*; @Entity @Table(name = "products") public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(length = 64, nullable = false, unique = true) private String name; private float price; public Product() { } public Product(String name, float price) { this(null, name, price); } public Product(Integer id) { this.id = id; } public Product(Integer id, String name, float price) { this.id = id; this.name = name; this.price = price; } // standard getters and setters }This is a simple entity class that maps to products table in the database. If you are new to Hibernate, I recommend you to follow this tutorial: Java Hibernate JPA Annotations Tutorial for Beginners.
package net.codejava; import org.hibernate.SessionFactory; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; public class HibernateUtil { public static SessionFactory getSessionFactory() { final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .configure() // configures settings from hibernate.cfg.xml .build(); SessionFactory factory = new MetadataSources(registry) .buildMetadata().buildSessionFactory(); return factory; } }This utility class simply returns a SessionFactory which is then used to perform CRUD operations. It is useful when using Hibernate in a standalone, simple Java application.
<?xml version="1.0" encoding="UTF-8"?> <hibernate-configuration> <session-factory> <property name="connection.url">jdbc:mysql://localhost:3306/testdb</property> <property name="connection.username">root</property> <property name="connection.password">password</property> <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="hibernate.hbm2ddl.auto">create-drop</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <mapping class="net.codejava.Product" /> </session-factory> </hibernate-configuration>In this Hibernate configuration file, I use the property hibernate.hbm2ddl.auto=create-drop so Hibernate will create the database table at runtime, and drop it when finished. So you just need to create the database testdb in MySQL server.
package net.codejava; import java.util.List; import org.hibernate.*; import org.hibernate.query.*; import org.junit.jupiter.api.*; public class HibernateUtilTest { private static SessionFactory sessionFactory; private Session session; @BeforeAll public static void setup() { sessionFactory = HibernateUtil.getSessionFactory(); System.out.println("SessionFactory created"); } @AfterAll public static void tearDown() { if (sessionFactory != null) sessionFactory.close(); System.out.println("SessionFactory destroyed"); } @Test public void testCreate() { } @Test public void testUpdate() { } @Test public void testGet() { } @Test public void testList() { } @Test public void testDelete() { } @BeforeEach public void openSession() { session = sessionFactory.openSession(); System.out.println("Session created"); } @AfterEach public void closeSession() { if (session != null) session.close(); System.out.println("Session closed\n"); } }As you can see, I use lifecycle methods in JUnit to initialize SessionFactory before all test methods, initialize Session before each test method, and close them accordingly. I think this example explains the use of JUnit’s lifecycle methods perfectly.Update the test method that tests persisting a product as follows:
@Test public void testCreate() { System.out.println("Running testCreate..."); session.beginTransaction(); Product product = new Product("iPhone 10", 699); Integer id = (Integer) session.save(product); session.getTransaction().commit(); Assertions.assertTrue(id > 0); }Write code for the testUpdate() method:
@Test public void testUpdate() { System.out.println("Running testUpdate..."); Integer id = 1; Product product = new Product(id, "iPhone 11", 999); session.beginTransaction(); session.update(product); session.getTransaction().commit(); Product updatedProduct = session.find(Product.class, id); assertEquals("iPhone 11", updatedProduct.getName()); }For testing retrieval operations, we test get a specific product and get all products. Update the testGet() method with below code:
@Test public void testGet() { System.out.println("Running testGet..."); Integer id = 1; Product product = session.find(Product.class, id); assertEquals("iPhone 10", product.getName()); }Code for the testList() method:
@Test public void testList() { System.out.println("Running testList..."); Query<Product> query = session.createQuery("from Product", Product.class); List<Product> resultList = query.getResultList(); Assertions.assertFalse(resultList.isEmpty()); }And the last test method is for testing delete operation:
@Test public void testDelete() { System.out.println("Running testDelete..."); Integer id = 1; Product product = session.find(Product.class, id); session.beginTransaction(); session.delete(product); session.getTransaction().commit(); Product deletedProduct = session.find(Product.class, id); Assertions.assertNull(deletedProduct); }You can run each test individually. Note that run the testCreate() method first to create the table and first row. Then set hibernate.hbm2ddl.auto=none to keep the data for subsequent tests. You can execute all test methods by using test method order, as described in this guide.For visual actions, I recommend you to watch the following video: