Machine Coding Problem

Unit Testing Framework

maco60macoAllinfrastructurereflectionannotation-logic
Commonly Asked By:JetBrainsMicrosoftGoogle

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: BeforeAllBeforeTestAfterAfterAll.
  • 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 ===");
    }
}