Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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 – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

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

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

Course – LJU – NPI (tag = JUnit)
announcement - icon

Master the most popular testing framework for Java, through the Learn JUnit course:

>> LEARN JUNIT

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

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Overview

In this tutorial, we’re going to take a look at the Rules feature provided by the JUnit 4 library.

We’ll begin by introducing the JUnit Rules Model before walking through the most important base rules provided by the distribution. Additionally, we’ll also see how to write and use our own custom JUnit Rule.

To learn more about testing with JUnit, check out our comprehensive JUnit series.

Note that if you’re using JUnit 5, rules have been replaced by the Extension model.

2. Introduction to JUnit 4 Rules

JUnit 4 rules provide a flexible mechanism to enhance tests by running some code around a test case execution. In some sense, it’s similar to having @Before and @After annotations in our test class.

Let’s imagine we wanted to connect to an external resource such as a database during test setup and then close the connection after our test finishes. If we want to use that database in multiple tests, we’d end up duplicating that code in every test.

By using a rule, we can have everything isolated in one place and reuse the code easily from multiple test classes.

3. Using JUnit 4 Rules

So how can we use rules? We can use JUnit 4 rules by following these simple steps:

  • Add a public field to our test class and ensure that the type of this field is a subtype of the org.junit.rules.TestRule interface
  • Annotate the field with the @Rule annotation

In the next section, we’ll see what project dependencies we need to get started.

4. Maven Dependencies

First, let’s add the project dependencies we’ll need for our examples. We’ll only need the main JUnit 4 library:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

As always, we can get the latest version from Maven Central.

5. Rules Provided in the Distribution

Of course, JUnit provides a number of useful, predefined rules as part of the library. We can find all these rules in the org.junit.rules package.

In this section, we’ll see some examples of how to use them.

5.1. The TemporaryFolder Rule

When testing, we often need access to a temporary file or folder. However, managing the creation and deletion of these files can be cumbersome. Using the TemporaryFolder rule, we can manage the creation of files and folders that should be deleted when the test method terminates:

@Rule
public TemporaryFolder tmpFolder = new TemporaryFolder();

@Test
public void givenTempFolderRule_whenNewFile_thenFileIsCreated() throws IOException {
    File testFile = tmpFolder.newFile("test-file.txt");

    assertTrue("The file should have been created: ", testFile.isFile());
    assertEquals("Temp folder and test file should match: ", 
      tmpFolder.getRoot(), testFile.getParentFile());
}

As we can see, we first define the TemporaryFolder rule tmpFolder. Next, our test method creates a file called test-file.txt in the temporary folder. We then check that the file has been created and exists where it should. Really nice and simple!

When the test finishes, the temporary folder and file should be deleted. However, this rule doesn’t check whether or not the deletion is successful.

There are also a few other interesting methods worth mentioning in this class:

  • newFile()

    If we don’t provide any file name, then this method creates a randomly named new file.

  • newFolder(String... folderNames)

    To create recursively deep temporary folders, we can use this method.

  • newFolder()

    Likewise, the newFolder() method creates a randomly named new folder.

A nice addition worth mentioning is that starting with version 4.13, the TemporaryFolder rule allows verification of deleted resources:

@Rule 
public TemporaryFolder folder = TemporaryFolder.builder().assureDeletion().build();

If a resource cannot be deleted, the test with fail with an AssertionError.

Finally, in JUnit 5, we can achieve the same functionality using the Temporary Directory extension.

5.2. The ExpectedException Rule

As the name suggests, we can use the ExpectedException rule to verify that some code throws an expected exception:

@Rule
public final ExpectedException thrown = ExpectedException.none();

@Test
public void givenIllegalArgument_whenExceptionThrown_MessageAndCauseMatches() {
    thrown.expect(IllegalArgumentException.class);
    thrown.expectCause(isA(NullPointerException.class));
    thrown.expectMessage("This is illegal");

    throw new IllegalArgumentException("This is illegal", new NullPointerException());
}

As we can see in the example above, we’re first declaring the ExpectedException rule. Then, in our test, we’re asserting that an IllegalArgumentException is thrown.

Using this rule, we can also verify some other properties of the exception, such as the message and cause.

For an in-depth guide to testing exceptions with JUnit, check out our excellent guide on how to Assert an Exception.

5.3. The TestName Rule

Put simply, the TestName rule provides the current test name inside a given test method:

@Rule public TestName name = new TestName();

@Test
public void givenAddition_whenPrintingTestName_thenTestNameIsDisplayed() {
    LOG.info("Executing: {}", name.getMethodName());
    assertEquals("givenAddition_whenPrintingTestName_thenTestNameIsDisplayed", name.getMethodName());
}

In this trivial example, when we run the unit test, we should see the test name in the output:

INFO  c.baeldung.rules.JUnitRulesUnitTest - 
    Executing: givenAddition_whenPrintingTestName_thenTestNameIsDisplayed

5.4. The Timeout Rule

In this next example, we’ll take a look at the Timeout rule. This rule offers a useful alternative to using the timeout parameter on an individual Test annotation.

Now, let’s see how to use this rule to set a global timeout on all the test methods in our test class:

@Rule
public Timeout globalTimeout = Timeout.seconds(10);

@Test
public void givenLongRunningTest_whenTimout_thenTestFails() throws InterruptedException {
    TimeUnit.SECONDS.sleep(20);
}

In the above trivial example, we first define a global timeout for all test methods of 10 seconds. Then we deliberately define a test which will take longer than 10 seconds.

When we run this test, we should see a test failure:

org.junit.runners.model.TestTimedOutException: test timed out after 10 seconds
...

5.5. The ErrorCollector Rule

Next up we’re going to take a look at the ErrorCollector rule. This rule allows the execution of a test to continue after the first problem is found.

Let’s see how we can use this rule to collect all the errors and report them all at once when the test terminates:

@Rule 
public final ErrorCollector errorCollector = new ErrorCollector();

@Test
public void givenMultipleErrors_whenTestRuns_thenCollectorReportsErrors() {
    errorCollector.addError(new Throwable("First thing went wrong!"));
    errorCollector.addError(new Throwable("Another thing went wrong!"));
        
    errorCollector.checkThat("Hello World", not(containsString("ERROR!")));
}

In the above example, we add two errors to the collector. When we run the test, the execution continues, but the test will fail at the end.

In the output, we will see both errors reported:

java.lang.Throwable: First thing went wrong!
...
java.lang.Throwable: Another thing went wrong!

5.6. The Verifier Rule

The Verifier rule is an abstract base class that we can use when we wish to verify some additional behavior from our tests. In fact, the ErrorCollector rule we saw in the last section extends this class.

Let’s now take a look at a trivial example of defining our own verifier:

private List messageLog = new ArrayList();

@Rule
public Verifier verifier = new Verifier() {
    @Override
    public void verify() {
        assertFalse("Message Log is not Empty!", messageLog.isEmpty());
    }
};

Here, we define a new Verifier and override the verify() method to add some extra verification logic. In this straightforward example, we simply check to see that the message log in our example isn’t empty.

Now, when we run the unit test and add a message, we should see that our verifier has been applied:

@Test
public void givenNewMessage_whenVerified_thenMessageLogNotEmpty() {
    // ...
    messageLog.add("There is a new message!");
}

5.7. The DisableOnDebug Rule

Sometimes we may want to disable a rule when we’re debugging. For example, it’s often desirable to disable a Timeout rule when debugging to avoid our test timing out and failing before we’ve had time to debug it properly.

The DisableOnDebug Rule does precisely this and allows us to label certain rules to be disabled when debugging:

@Rule
public DisableOnDebug disableTimeout = new DisableOnDebug(Timeout.seconds(30));

In the example above we can see that in order to use this rule, we simply pass the rule we want to disable to the constructor.

The main benefit of this rule is that we can disable rules without making any modifications to our test classes during debugging.

5.8. The ExternalResource Rule

Typically, when writing integration tests, we may wish to set up an external resource before a test and tear it down afterward. Thankfully, JUnit provides another handy base class for this.

We can extend the abstract class ExternalResource to set up an external resource before a test, such as a file or a database connection. In fact, the TemporaryFolder rule we saw earlier extends ExternalResource.

Let’s take a quick look at how we could extend this class:

@Rule
public final ExternalResource externalResource = new ExternalResource() {
    @Override
    protected void before() throws Throwable {
        // code to set up a specific external resource.
    };
    
    @Override
    protected void after() {
        // code to tear down the external resource
    };
};

In this example, when we define an external resource we simply need to override the before() method and after() method in order to set up and tear down our external resource.

6. Applying Class Rules

Up until now, all the examples we’ve looked at have applied to single test case methods. However, sometimes we might want to apply a rule at the test class level. We can accomplish this by using the @ClassRule annotation.

This annotation works very similarly to @Rule but wraps a rule around a whole test — the main difference being that the field we use for our class rule must be static:

@ClassRule
public static TemporaryFolder globalFolder = new TemporaryFolder();

7. Defining a Custom JUnit Rule

As we’ve seen, JUnit 4 provides a number of useful rules out of the box. Of course, we can define our own custom rules. To write a custom rule, we need to implement the TestRule interface.

Let’s take a look at an example of defining a custom test method name logger rule:

public class TestMethodNameLogger implements TestRule {

    private static final Logger LOG = LoggerFactory.getLogger(TestMethodNameLogger.class);

    @Override
    public Statement apply(Statement base, Description description) {
        logInfo("Before test", description);
        try {
            return new Statement() {
                @Override
                public void evaluate() throws Throwable {
                    base.evaluate();
                }
            };
        } finally {
            logInfo("After test", description);
        }
    }

    private void logInfo(String msg, Description description) {
        LOG.info(msg + description.getMethodName());
    }
}

As we can see, the TestRule interface contains one method called apply(Statement, Description) that we must override to return an instance of Statement. The statement represents our tests within the JUnit runtime. When we call the evaluate() method, this executes our test.

In this example, we log a before and after message and include from the Description object the method name of the individual test.

8. Using Rule Chains

In this final section, we’ll take a look at how we can order several test rules using the RuleChain rule:

@Rule
public RuleChain chain = RuleChain.outerRule(new MessageLogger("First rule"))
    .around(new MessageLogger("Second rule"))
    .around(new MessageLogger("Third rule"));

In the above example, we create a chain of three rules that simply print out the message passed to each MessageLogger constructor.

When we run our test, we’ll see how the chain is applied in order:

Starting: First rule
Starting: Second rule
Starting: Third rule
Finished: Third rule
Finished: Second rule
Finished: First rule

9. Conclusion

To summarize, in this tutorial, we’ve explored JUnit 4 rules in detail.

First, we started by explaining what rules are and how we can use them. Next, we took an in-depth look at the rules that come as part of the JUnit distribution.

Finally, we looked at how we can define our own custom rule and how to chain rules together.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
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.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

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

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

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

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

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

eBook Jackson – NPI EA – 3 (cat = Jackson)