eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

Partner – LambdaTest – NPI (cat= Testing)
announcement - icon

Regression testing is an important step in the release process, to ensure that new code doesn't break the existing functionality. As the codebase evolves, we want to run these tests frequently to help catch any issues early on.

The best way to ensure these tests run frequently on an automated basis is, of course, to include them in the CI/CD pipeline. This way, the regression tests will execute automatically whenever we commit code to the repository.

In this tutorial, we'll see how to create regression tests using Selenium, and then include them in our pipeline using GitHub Actions:, to be run on the LambdaTest cloud grid:

>> How to Run Selenium Regression Tests With GitHub Actions

1. Overview

In real-world automation, we often need to enable or disable tests based on runtime conditions, such as the environment (stage or production), feature flags, configuration, CI/CD parameters, and so on.

In this tutorial, we’ll walkthrough different approaches to conditionally skip tests in TestNG.

2. Understanding the Problem

In TestNG, we can disable a test by using @Test with a parameter “enabled” with a boolean value false:

@Test(enabled=false)
public void givenNumbers_sumEquals_thenCorrect() {
    int sum = numbers.stream().reduce(0, Integer::sum);
    Assert.assertEquals(6, sum);
}

The above code works because Java annotations are evaluated at compile time, not runtime. This means the code below is invalid in Java:

@Test(enabled = isEnabled())
public void givenNumbers_sumEquals_thenCorrect() {
}

TestNG can’t evaluate runtime conditions inside annotations. It’s the reason that method calls, expressions, and variables are not allowed. We can solve this by using a mechanism that evaluates conditions at runtime, during test discovery, or execution.

3. Throwing SkipException

TestNG provides a built-in SkipException that allows us to skip tests programmatically. When we throw it, TestNG marks the test as SKIPPED, not FAILED. We can use this to skip tests programmatically based on runtime conditions. 

We can throw SkipException from different places in our test code. The mechanism stays the same, only the location changes. Let’s explore both approaches:

3.1. Skipping Inside the Test Method

In this approach, TestNG discovers and invokes the test method as usual. Inside the test, we check the condition at runtime. If the condition is met, we throw SkipException, which tells TestNG to skip the rest of the test:

@Test
public void givenConditions_whenUsingSkipException_thenSkipTest() {
    if (shouldSkipTest()) {
        throw new SkipException("Skipping test for Demonstration!");
    }
    System.out.println("This line won't get printed");
}

public boolean shouldSkipTest() {
    return true;
}

Running the above test returns the following output:

Test ignored.

===============================================
Default Suite
Total tests run: 1, Passes: 0, Failures: 0, Skips: 1
===============================================

Here, we’re placing the skip logic inside the test method. This can hurt readability. If we need to skip multiple tests, we must duplicate the logic in each one. Rather than checking conditions in every test, we can centralize the skip logic in lifecycle hooks. 

3.2. Skipping Using @BeforeMethod

TestNG always executes configuration methods such as @BeforeMethod and @BeforeClass before running a test. When we throw SkipException from these methods, TestNG treats it as a deliberate skip. It aborts the test immediately and marks it as SKIPPED. The test method never runs:

public class SkipExceptionInSetupUnitTest {
    @BeforeMethod
    public void givenConditions_whenUsingSkipException_thenSkipTest() {
        if (shouldSkipTest()) {
            throw new SkipException("Skipping tests for UK region");
        }
    }

    public boolean shouldSkipTest() {
        return true;
    }

    @Test
    public void givenSkipConditionInSetup_whenUsingSkipException_thenSkipTest() {
        System.out.println("Dummy Test!");
    }

    @Test
    public void givenSkipConditionInSetup_whenUsingSkipException_thenSkipTest2() {
        System.out.println("Dummy Test 2!");
    }
}

Running the above tests returns the following output:

Test ignored.

Test ignored.

===============================================
Default Suite
Total tests run: 2, Passes: 0, Failures: 0, Skips: 2
Configuration Failures: 0, Skips: 2
===============================================

This approach skips all tests in the class. It gives us less granular control. We should use this when multiple tests share the same runtime condition. It helps us avoid duplicating skip logic in each test.

4. Implementing an IAnnotationTransformer

IAnnotationTransformer is a TestNG listener interface that allows us to modify test annotations at runtime. TestNG calls its transform() method before processing each @Test annotation. We can dynamically change attributes like enabled, priority, or groups without modifying the source code. This is useful for enabling or disabling tests based on runtime conditions:

public class SkipAnnotationTransformer implements IAnnotationTransformer {
    @Override
    public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
        if (testMethod != null && isTargetTestClass(testMethod) && shouldSkipTest()) {
            annotation.setEnabled(false);
        }
    }

    private boolean isTargetTestClass(Method testMethod) {
        return testMethod.getDeclaringClass().equals(SkipAnnotationTransformerUnitTest.class);
    }

    public boolean shouldSkipTest() {
        return true;
    }
}

In the transform() method, we check if the test method belongs to SkipAnnotationTransformerUnitTest and if shouldSkipTest() returns true. When both conditions are met, we set annotation.setEnabled(false). It completely disables the test – TestNG never schedules the test, never runs configuration methods, and never includes it in test counts.

In the testng.xml file, we register our SkipAnnotationTransformer as a listener using the <listeners> tag. We define a test suite that scans all packages matching com.baeldung.testng.* to automatically discover and run test classes:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Test Suite">
    <listeners>
        <listener class-name="com.baeldung.testng.conditionalskip.SkipAnnotationTransformer"/>
    </listeners>
    <test name="All Tests">
        <packages>
            <package name="com.baeldung.testng.*"/>
        </packages>
    </test>
</suite>

We configure the Maven Surefire Plugin to run our TestNG tests. We add the surefire-testng dependency to force Surefire to use the TestNG provider instead of auto-detecting Junit. We point Surefire to our testng.xml file using  <suiteXmlFiles> so it uses our suite configuration:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.2.5</version>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven.surefire</groupId>
            <artifactId>surefire-testng</artifactId>
            <version>3.2.5</version>
        </dependency>
    </dependencies>
    <configuration>
        <suiteXmlFiles>
            <suiteXmlFile>src/test/resources/testng.xml</suiteXmlFile>
        </suiteXmlFiles>
    </configuration>
</plugin>

We define our test cases in the SkipAnnotationTransformerUnitTest, which we’ll be running to verify the transformer behaviour:

public class SkipAnnotationTransformerUnitTest {
    @Test
    public void givenSkipAnnotation_whenUsingIAnnotationTransformer_thenSkipTest() {
        System.out.println("Dummy Test!");
    }

    @Test
    public void givenSkipAnnotation_whenUsingIAnnotationTransformer_thenSkipTest2() {
        System.out.println("Dummy Test 2!");
    }
}

For running the SkipAnnotationTransformerUnitTest only, we’ve created a demo testng-transformer-demo.xml file:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Transformer Demo Suite">
    <listeners>
        <listener class-name="com.baeldung.testng.conditionalskip.SkipAnnotationTransformer"/>
    </listeners>
    <test name="Transformer Demo">
        <classes>
            <class name="com.baeldung.testng.conditionalskip.SkipAnnotationTransformerUnitTest"/>
        </classes>
    </test>
</suite>

Now, we’ll run the test using the following command:

mvn test -Dsurefire.suiteXmlFiles=src/test/resource/testng-transformer-demo.xml

We don’t see the tests defined in SkipAnnotationTransformerUnitTest as either running or skipped. TestNG ignores them completely.

5. Conclusion

In this article, we discussed various approaches to ignore a test in TestNG conditionally.

We can throw SkipException for the simplest and most explicit approach. However, this applies to skip decisions during test execution, not during discovery. The primary advantage is visibility, as skipped tests are explicitly reported as “SKIPPED”.

Alternatively, we can use IAnnotationTransformer, which operates earlier during test discovery. We disable tests that don’t meet the condition before execution begins, so they never run and never appear as skipped. This results in clean counts and faster execution.

Choosing between these depends on whether we need report transparency or execution cleanliness. 

As always, the code is available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)
guest
0 Comments
Oldest
Newest
Inline Feedbacks
View all comments