Functional Scope (In-Scope)
- Metadata Annotation / Decorator Discovery: Inspecting, querying, and cataloging target test class behaviors via reflections.
- Structured Test LifeCycle: Executing hooks in fixed ordering:
BeforeAll→Before→Test→After→AfterAll. - Rigorous Assertion Library: Supporting absolute equality checks, boolean validations, and exception capture testing.
- Test Case Isolation: Guaranteeing zero state pollution by instantiating fresh test classes per method run.
Explicit Boundaries (Out-of-Scope)
- Dynamic File Scanning: Recursively parsing files on disk to find classes or directory watchers (focused purely on runtime class reflection).
- Mocking / Stubbing Frameworks: Dynamic proxy generation or bytecode manipulation to replace target system dependencies (e.g. Mockito features).
Clean reference designs demonstrating dynamic metadata scanning and lifecycle runners in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.lang.annotation.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Test {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Before {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface After {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface BeforeAll {}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface AfterAll {}
class Assert {
public static void assertEquals(Object expected, Object actual) {
if (!Objects.equals(expected, actual)) {
throw new AssertionError("Expected " + expected + " but got " + actual);
}
}
public static void assertTrue(boolean condition) {
if (!condition) {
throw new AssertionError("Expected true but got false");
}
}
public static <T extends Throwable> void assertThrows(Class<T> expectedException, Runnable executable) {
try {
executable.run();
} catch (Throwable t) {
if (expectedException.isInstance(t)) {
return; // Success
}
throw new AssertionError("Expected exception of type " + expectedException.getName() + " but got " + t.getClass().getName());
}
throw new AssertionError("Expected exception of type " + expectedException.getName() + " but none was thrown");
}
}
enum TestStatus { PASS, FAIL, ERROR }
class TestResult {
private final String name;
private final TestStatus status;
private final Throwable failureReason;
public TestResult(String name, TestStatus status, Throwable failureReason) {
this.name = name;
this.status = status;
this.failureReason = failureReason;
}
public String getName() { return name; }
public TestStatus getStatus() { return status; }
public Throwable getFailureReason() { return failureReason; }
@Override
public String toString() {
return "TestResult{name='" + name + "', status=" + status + ", reason=" + (failureReason != null ? failureReason.toString() : "None") + "}";
}
}
class TestRunner {
public List<TestResult> run(Class<?> testClass) {
List<TestResult> results = Collections.synchronizedList(new ArrayList<>());
List<Method> testMethods = new ArrayList<>();
List<Method> beforeMethods = new ArrayList<>();
List<Method> afterMethods = new ArrayList<>();
List<Method> beforeAllMethods = new ArrayList<>();
List<Method> afterAllMethods = new ArrayList<>();
for (Method method : testClass.getDeclaredMethods()) {
if (method.isAnnotationPresent(Test.class)) testMethods.add(method);
if (method.isAnnotationPresent(Before.class)) beforeMethods.add(method);
if (method.isAnnotationPresent(After.class)) afterMethods.add(method);
if (method.isAnnotationPresent(BeforeAll.class)) beforeAllMethods.add(method);
if (method.isAnnotationPresent(AfterAll.class)) afterAllMethods.add(method);
}
try {
// Run BeforeAll
for (Method m : beforeAllMethods) {
m.invoke(null); // Expect static methods
}
if (!testMethods.isEmpty()) {
java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newFixedThreadPool(4);
try {
java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(testMethods.size());
for (Method testMethod : testMethods) {
executor.submit(() -> {
try {
Object instance = testClass.getDeclaredConstructor().newInstance();
Throwable failure = null;
TestStatus status = TestStatus.PASS;
try {
// Run Before
for (Method before : beforeMethods) {
before.invoke(instance);
}
// Run Test
testMethod.invoke(instance);
} catch (InvocationTargetException ite) {
Throwable cause = ite.getCause();
if (cause instanceof AssertionError) {
status = TestStatus.FAIL;
} else {
status = TestStatus.ERROR;
}
failure = cause;
} catch (Exception e) {
status = TestStatus.ERROR;
failure = e;
} finally {
// Run After
try {
for (Method after : afterMethods) {
after.invoke(instance);
}
} catch (Exception e) {
status = TestStatus.ERROR;
failure = e;
}
}
results.add(new TestResult(testMethod.getName(), status, failure));
} catch (Exception e) {
results.add(new TestResult(testMethod.getName(), TestStatus.ERROR, e));
} finally {
latch.countDown();
}
});
}
latch.await();
} finally {
executor.shutdown();
}
}
// Run AfterAll
for (Method m : afterAllMethods) {
m.invoke(null); // Expect static methods
}
} catch (Exception e) {
System.err.println("Lifecycle initialization error: " + e.getMessage());
}
return results;
}
}
// ─── DEMO TEST SUITE FOR REFLECTION SCANNING ─────────────────────────────────
class MathTestSuite {
private static int globalCounter = 0;
private int localState = 0;
@BeforeAll
public static void initAll() {
globalCounter = 100;
System.out.println("[MathTestSuite] @BeforeAll invoked. globalCounter = " + globalCounter);
}
@Before
public void initEach() {
localState = 5;
System.out.println("[MathTestSuite] @Before invoked. localState = " + localState);
}
@Test
public void testAdditionSuccess() {
System.out.println("[MathTestSuite] Executing testAdditionSuccess");
Assert.assertEquals(10, localState + 5);
}
@Test
public void testAssertionFailure() {
System.out.println("[MathTestSuite] Executing testAssertionFailure");
Assert.assertEquals(12, localState + 5);
}
@Test
public void testRuntimeError() {
System.out.println("[MathTestSuite] Executing testRuntimeError");
String nullString = null;
nullString.length(); // Throws NullPointerException
}
@After
public void cleanupEach() {
System.out.println("[MathTestSuite] @After invoked.");
}
@AfterAll
public static void cleanupAll() {
System.out.println("[MathTestSuite] @AfterAll invoked.");
}
}
public class Main {
public static void main(String[] args) {
System.out.println("=== RUNNING UNIT TESTING FRAMEWORK DEMO ===");
TestRunner runner = new TestRunner();
List<TestResult> results = runner.run(MathTestSuite.class);
System.out.println("\n=== TEST RESULTS REPORT ===");
for (TestResult result : results) {
System.out.println(result);
}
System.out.println("=== SIMULATION COMPLETE ===");
}
}