What makes JUnit the most popular Java Framework
JUnit is the most popular and widely used framework for unit testing in Java. Recent surveys show that it is also the most commonly included external library in Java projects.
But what made JUnit so easy to use and hence so popular among developers? And is there any common feature between all Java frameworks that became de facto standards in their space, like Spring for dependency injection, Hibernate for ORM, and others?
In this article, we are going to explore the 2 features formula that makes any Java library a hit among Java developers.
Java Annotations
The first feature that makes a library or framework easy to use, manage and configure is Annotations.
In addition to all the typical programming language constructs that express the program’s flow (like variable declarations, conditions, loops, expressions, etc), and the organizational building blocks that force our programs to be structured in an Object-Oriented style (like classes, interfaces, etc), Java also allows “marking” many such constructs with Annotations.
Examples:
@Bean @Scheduled(5) @Test(timeout = 500)
These odd, behavior-less markings are one of the most powerful features in Java and don’t exist in many other languages.
Since they don’t have any behavior by default, what gives them the behavior and enriches our codebase is the logic that looks for those Annotations and makes decisions based on:
The presence or absence of an Annotation
The Annotation type
Values assigned inside the Annotation parentheses
For example, JUnit looks for methods annotated with @Test and if it encounters a method annotated with
@Test(timeout = 500)
JUnit knows that a test that runs longer than 500ms is considered a failure, all based on the value of 500 assigned to timeout attribute of the @Test annotation.
To discover Annotations throughout the codebase and assign behavior to the annotated constructs (such as methods, classes and fields) we need the second feature in our success formula: Java Reflection.
Java Reflection
As we just mentioned, Annotations on their own don’t have any behavior or functionality. The mechanism that brings Annotations to life at Runtime is called Java Reflection.
Reflection API which is our way to use that feature using Java code, allows a program to inspect a class at runtime, and among others allows our a library like JUnit to look for and discover Annotations that are specifically marked for discovery at Runtime. Once an Annotation is discovered, certain behavior can be performed, which we can express in simple Java code.
For example, we provide JUnit with the following code that expresses a test suite:
public class TestOnlineStore { @BeforeClass public static void initFakeDatabase() { .... } @Before public void prepareTest() { .... } @Test public void testTransaction() { ... } @Test public void testRefund() { ... } }
When we run JUnit, it will inspect the TestOnlineStore class and look for the @BeforeClass annotation to find which method JUnit should run as a one-time preparation for the test suite. Once the annotation is discovered, the initFakeDataBase() method will be executed. Notice that the name of the method is not significant and JUnit will run a method with any name as long as it is annotated with @BeforeClass and has the appropriate signature. The method execution is also done using Reflection. Similarly, JUnit will proceed to find all the methods annotated with the @Before annotation and dynamically call them before every test. And finally, JUnit will find all the methods annotated with @Test annotation, and call those methods using Reflection as well.
The Formula
To summarize, Annotations allow us to declaratively assign roles to arbitrary code, and Java Reflection assigns that behavior to each Annotation. When we run JUnit, the library uses those two features together to find, execute and analyze our tests and provide us the result.
Using Annotations and Java Reflection we can create a framework that empowers developers without forcing them to write any complicated code, removing unnecessary barriers and boilerplate. All developers need to do is express their logic and intent through simple and non-obtrusive Annotations in the right places, and that’s it, the library Reflection based code, will do the rest.
Benefits of Mastering Java Reflection
If you want to be a true Senior Software Developer, Java Reflection is the most important topic you need to master. A true Senior Java Developer doesn’t just use off-the-shelf libraries but understands how they work to make the best use of them.
More importantly, a Senior Java Developer can write Java code which can be reused by many other engineers in their team or organization, and Java Reflection is the most important tool that allows creating generic algorithms and libraries.
If you want to step up your game and learn how to build your own Reflection based algorithms and libraries, the Advanced Java Topics: Java Reflection - Master Class is the best online resource to master those skills.
In this course, you will learn all the essential Reflection APIs through real-life examples. More importantly, you will learn Reflection best practices and rules of thumb on how to use Reflection safely and correctly to get the most benefit and performance for your application.
Follow this link and join thousands of Java Developers to Java Reflection mastery.