FIRST Principles Unit Tests | Java Fresher Interview
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
FIRST stands for Fast, Independent, Repeatable, Self-validating, and Timely. Together, these principles make a test suite dependable and practical to run.
Fast means feedback arrives soon enough that developers use the suite regularly. It is not a fixed rule such as every test taking less than 50 milliseconds: a small unit test and a database integration test have different jobs and costs. Independent means one test does not require another test to run first. Repeatable means controlled inputs give the same result, which is why code that reads the current time can accept a Clock and tests can supply Clock.fixed(...). Self-validating means assertions clearly decide whether the behavior is correct. Timely means the test is written close to the production change rather than being postponed until the behavior is forgotten.
For example, an order service can receive both its repository and clock through its constructor. Its unit test supplies a fake repository and a fixed clock, calls placeOrder, and asserts the saved timestamp. That test is isolated, repeatable, and self-validating. A repository test may still use a real test database because its purpose is to check persistence; FIRST asks us to keep that test focused and reasonably fast, not to replace every real dependency blindly.
FIRST Principles Unit Tests | Java Fresher Interview
Direct Answer
FIRST stands for Fast, Independent, Repeatable, Self-validating, and Timely. Tests should give quick feedback, not depend on one another, produce the same result under the same conditions, decide pass or fail through assertions, and be written close to the production code they verify.
Code Example
import java.time.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class OrderService {
private final OrderRepository repo;
private final Clock clock; // injected -> Repeatable
OrderService(OrderRepository repo, Clock clock) { this.repo = repo; this.clock = clock; }
Order placeOrder(Long userId, String item) {
return repo.save(new Order(userId, item, LocalDateTime.now(clock)));
}
}
class OrderServiceTest {
@Test
void placeOrder_whenCalled_thenStampsTheFixedTime() {
var fixedTime = LocalDateTime.of(2024, 1, 15, 10, 30);
var clock = Clock.fixed(fixedTime.toInstant(ZoneOffset.UTC), ZoneOffset.UTC);
var repo = mock(OrderRepository.class);
when(repo.save(any())).thenAnswer(inv -> inv.getArgument(0));
var service = new OrderService(repo, clock);
Order saved = service.placeOrder(100L, "Laptop");
assertEquals(fixedTime, saved.getTimestamp()); // Repeatable: time is controlled
}
}
Common Mistakes & Pitfalls
- Using a broader boundary than the question needs — a unit rule may need only direct construction, while a repository query needs a database test. Do not replace the real boundary merely to satisfy a speed slogan.
- Breaking Independent with shared state — a static counter, reused database row, or shared file can create order dependencies. Isolate or clean up the owned state.
- Ignoring Repeatable inputs — record random seeds, control wall-clock time, and make locale, zone, and environment assumptions explicit.
Check your understanding
Answer these without looking back at the article.
- What is a flaky test and how do you fix it?
- How do you inject the current time in tests to make them Repeatable?
- What happens to test quality when tests are written long after the code?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.