logo
eng-flag

JUnit Cheatsheet

Table of Contents

  1. Setup
  2. Basic Annotations
  3. Assertions
  4. Test Lifecycle
  5. Parameterized Tests
  6. Assumptions
  7. Timeouts
  8. Exception Testing
  9. Test Suites
  10. Advanced Features
  11. Best Practices

Setup

Maven Dependency

Add this to your pom.xml:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

Gradle Dependency

Add this to your build.gradle:

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.2'

Basic Annotations

import org.junit.jupiter.api.*;

public class MyTest {
    @Test
    void testMethod() {
        // Test code here
    }

    @BeforeEach
    void setUp() {
        // Runs before each test
    }

    @AfterEach
    void tearDown() {
        // Runs after each test
    }

    @BeforeAll
    static void setUpAll() {
        // Runs once before all tests in the class
    }

    @AfterAll
    static void tearDownAll() {
        // Runs once after all tests in the class
    }

    @Disabled("Reason for disabling")
    @Test
    void disabledTest() {
        // This test will not run
    }
}

Assertions

import static org.junit.jupiter.api.Assertions.*;

@Test
void testAssertions() {
    assertEquals(expected, actual);
    assertTrue(condition);
    assertFalse(condition);
    assertNull(object);
    assertNotNull(object);
    assertSame(expected, actual);
    assertNotSame(expected, actual);
    assertArrayEquals(expectedArray, actualArray);
    assertThrows(ExpectedException.class, () -> {
        // Code that should throw ExpectedException
    });
    assertAll("grouped assertions",
        () -> assertEquals(expected1, actual1),
        () -> assertEquals(expected2, actual2)
    );
}

Test Lifecycle

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LifecycleTest {
    @BeforeAll
    void initAll() {
        // Runs once before all test methods
    }

    @BeforeEach
    void init() {
        // Runs before each test method
    }

    @Test
    void testMethod1() {
        // Test code
    }

    @Test
    void testMethod2() {
        // Test code
    }

    @AfterEach
    void tearDown() {
        // Runs after each test method
    }

    @AfterAll
    void tearDownAll() {
        // Runs once after all test methods
    }
}

Parameterized Tests

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;

class ParameterizedTests {
    @ParameterizedTest
    @ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
    void palindromes(String candidate) {
        assertTrue(isPalindrome(candidate));
    }

    @ParameterizedTest
    @CsvSource({
        "apple,  1",
        "banana, 2",
        "'lemon, lime', 3"
    })
    void testWithCsvSource(String fruit, int rank) {
        assertNotNull(fruit);
        assertTrue(rank > 0);
    }

    @ParameterizedTest
    @EnumSource(TimeUnit.class)
    void testWithEnumSource(TimeUnit timeUnit) {
        assertNotNull(timeUnit);
    }

    @ParameterizedTest
    @MethodSource("stringProvider")
    void testWithMethodSource(String argument) {
        assertNotNull(argument);
    }

    static Stream<String> stringProvider() {
        return Stream.of("apple", "banana", "cherry");
    }
}

Assumptions

import static org.junit.jupiter.api.Assumptions.*;

@Test
void testOnlyOnDeveloperWorkstation() {
    assumeTrue("DEV".equals(System.getenv("ENV")));
    // remainder of test
}

@Test
void testOnlyOnCiServer() {
    assumeTrue("CI".equals(System.getenv("ENV")),
               () -> "Aborting test: not on CI server");
    // remainder of test
}

Timeouts

@Test
@Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
void timeoutTest() {
    // Test code that should complete within 500 milliseconds
}

Exception Testing

@Test
void exceptionTesting() {
    Exception exception = assertThrows(ArithmeticException.class, () -> {
        int result = 1 / 0;
    });

    assertEquals("/ by zero", exception.getMessage());
}

Test Suites

@Suite
@SelectClasses({
    TestClass1.class,
    TestClass2.class
})
class TestSuite {
    // This class remains empty
}

Advanced Features

Nested Tests

@Nested
class NestedTests {
    @Test
    void test1() {
        // Test code
    }

    @Test
    void test2() {
        // Test code
    }
}

Dynamic Tests

@TestFactory
Collection<DynamicTest> dynamicTests() {
    return Arrays.asList(
        dynamicTest("1st dynamic test", () -> assertTrue(true)),
        dynamicTest("2nd dynamic test", () -> assertEquals(4, 2 * 2))
    );
}

Test Interfaces

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
interface TestLifecycleLogger {
    @BeforeAll
    default void beforeAllTests() {
        System.out.println("Before all tests");
    }

    @AfterAll
    default void afterAllTests() {
        System.out.println("After all tests");
    }

    @BeforeEach
    default void beforeEachTest(TestInfo testInfo) {
        System.out.println("About to execute [" + testInfo.getDisplayName() + "]");
    }

    @AfterEach
    default void afterEachTest(TestInfo testInfo) {
        System.out.println("Finished executing [" + testInfo.getDisplayName() + "]");
    }
}

class TestInterfaceDemo implements TestLifecycleLogger {
    @Test
    void test1() {
        // Test code
    }
}

Best Practices

  1. Use descriptive test method names

    @Test
    void shouldReturnTrueWhenInputIsValid() {
        // Test code
    }
    
  2. Keep tests independent

    • Each test should be able to run independently of others
  3. Use @BeforeEach and @AfterEach for setup and teardown

    • Ensure each test starts with a clean state
  4. Group related tests using @Nested classes

    • Improves readability and organization
  5. Use parameterized tests for testing multiple inputs

    • Reduces code duplication
  6. Aim for fast tests

    • Use mocks or stubs for external dependencies
  7. Follow the AAA pattern: Arrange, Act, Assert

    @Test
    void testAddition() {
        // Arrange
        Calculator calc = new Calculator();
        
        // Act
        int result = calc.add(2, 3);
        
        // Assert
        assertEquals(5, result);
    }
    
  8. Use assumptions for environment-specific tests

    • Prevents tests from failing due to environment issues
  9. Avoid logic in tests

    • Tests should be straightforward and easy to understand
  10. Use assertAll for multiple related assertions

    • Ensures all assertions are checked, even if one fails

2024 © All rights reserved - buraxta.com