Learn how to create and run Citrus integration tests in just a few minutes. You can choose from a set of supported runtimes (JUnit, TestNG, Quarkus, SpringBoot, JBang) and domain specific languages (Java, XML, YAML, Groovy, Cucumber).
Quickstart
When writing a Citrus test you can choose from a set of supported programming languages and domain specific languages (DSL).
The Citrus Java DSL represents the most powerful way to write tests. Citrus provides a set of classes and methods to leverage the test code in form of a fluent API. Users can simply configure a test action with the different options using a fluent builder pattern style DSL.
In addition to that you can also write Citrus tests with XML, Groovy, YAML, Cucumber (Gherkin), Spring XML declaration files that get loaded as part of the test runtime. These test sources represent a more declarative approach of writing tests in Citrus. You do not necessarily need to know how to code Java when using one of these languages, but you may be limited in terms of customization opportunities.
See the following example to explore the different test source languages in Citrus.
@CitrusTest
public void helloWorldTest() {
variable("user", "Citrus");
$(echo().message("Hello from ${user}!"));
}
<test name="HelloWorldTest" xmlns="http://citrusframework.org/schema/xml/testcase">
<variables>
<variable name="user" value="Citrus"/>
</variables>
<actions>
<echo message="Hello from ${user}!"/>
</actions>
</test>
name: HelloWorldTest
variables:
- name: user
value: Citrus
actions:
- echo:
message: "Hello from ${user}!"
name "HelloWorldTest"
variables {
user="Citrus"
}
actions {
$(echo().message('Hello from ${user}!'))
}
Feature: HelloWorldTest
Background:
Given variables
| user | Citrus |
Scenario: Should Say Hello
Then print "Hello from ${user}!"

The easiest way to run a Citrus test is to use the Citrus JBang CLI tooling. This requires no project setup and no dependency management because everything is handled by JBang out of the box.
jbang citrus@citrusframework/citrus run helloWorld.yaml
TIP: You can install Citrus as a JBang app on your machine. This makes using the Citrus CLI even more comfortable because you can just call citrus run
for instance.
jbang trust add https://github.com/citrusframework/citrus/
jbang app install citrus@citrusframework/citrus
TIP: The init
> command creates a sample test in the chosen language for you.
citrus init helloWorld.yaml
citrus run helloWorld.yaml
The Citrus JBang support is fantastic to do fast prototyping. You just focus on writing the Citrus test code with fast and easy test execution via JBang. Once you are happy with the test you may want to move on to use one of the supported runtimes in Citrus in order to integrate the test into your project build lifecycle (e.g. via Maven and JUnit).
The Citrus test case is nothing but a normal Java unit test. Citrus integrates with standard unit test frameworks such as JUnit, TestNG or Cucumber as a runtime.
In addition to that Citrus also works with @QuarkusTest
and @SpringBootTest
annotated classes.
Most Java developers are familiar with at least one of the standard tools. Everything you can do with JUnit or TestNG you can do with Citrus tests, too. For instance, you can integrate the Citrus tests in a Maven build, run and debug Citrus from your favorite Java IDE or include Citrus tests into a continuous build pipeline.
Citrus supports multiple runtimes. The most prominent nowadays probably is JUnit Jupiter.
import org.citrusframework.TestCaseRunner;
import org.citrusframework.TestActionSupport;
import org.citrusframework.annotations.CitrusResource;
import org.citrusframework.annotations.CitrusTest;
import org.citrusframework.junit.jupiter.CitrusSupport;
import org.junit.jupiter.api.Test;
@CitrusSupport
public class HelloServiceIT implements TestActionSupport {
@CitrusResource
private TestCaseRunner t;
@Test
@CitrusTest
public void shouldSayHello() {
t.createVariable("user", "Citrus");
t.run(echo("Hello from ${user}!"));
}
}
import org.citrusframework.TestCaseRunner;
import org.citrusframework.TestActionSupport;
import org.citrusframework.annotations.CitrusResource;
import org.citrusframework.quarkus.CitrusSupport;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
@QuarkusTest
@CitrusSupport
public class HelloServiceIT implements TestActionSupport {
@CitrusResource
private TestCaseRunner t;
@Test
void shouldSayHello() {
t.createVariable("user", "Citrus");
t.run(echo("Hello from ${user}!"));
}
}
import org.citrusframework.TestCaseRunner;
import org.citrusframework.TestActionSupport;
import org.citrusframework.annotations.CitrusResource;
import org.citrusframework.config.CitrusSpringConfig;
import org.citrusframework.junit.jupiter.spring.CitrusSpringSupport;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.junit.jupiter.api.Test;
@SpringBootTest
@CitrusSpringSupport
@ContextConfiguration(classes = {CitrusSpringConfig.class})
public class HelloServiceIT implements TestActionSupport {
@CitrusResource
private TestCaseRunner t;
@Test
void shouldSayHello() {
t.createVariable("user", "Citrus");
t.run(echo("Hello from ${user}!"));
}
}
import org.testng.annotations.Test;
import org.citrusframework.TestActionSupport;
import org.citrusframework.annotations.CitrusTest;
import org.citrusframework.testng.TestNGCitrusSupport;
public class HelloServiceIT extends TestNGCitrusSupport implements TestActionSupport {
@Test
@CitrusTest
public void shouldSayHello() {
variable("user", "Citrus");
$(echo("Hello from ${user}!"));
}
}
import org.citrusframework.TestActionSupport;
import org.citrusframework.annotations.CitrusTest;
import org.citrusframework.junit.spring.JUnit4CitrusSupport;
import org.junit.Test;
public class HelloServiceIT extends JUnit4CitrusSupport implements TestActionSupport {
@Test
@CitrusTest
public void shouldSayHello() {
variable("user", "Citrus");
$(echo("Hello from ${user}!"));
}
}
@RunWith(Cucumber.class)
@CucumberOptions(
extraGlue = { "org.citrusframework.cucumber" },
plugin = { "pretty", "org.citrusframework.cucumber.CitrusReporter" } )
public class HelloServiceIT {
}
Now that you know how to run the Citrus tests it is time to explore the framework capabilities. In a typical use case scenario Citrus connects to different messaging transports and technologies such as Kafka, Http REST, JMS, Spring, Apache Camel, Testcontainers, Kubernetes, Knative, Selenium and many more.
Citrus combines with many frameworks and libraries and provides ready-to-use components and test actions to leverage the full power of integration testing. It is very easy to create an integration test case for messaging where the test sends a message to Kafka for instance to verify its outcome via response message validation.
import org.citrusframework.TestActionSupport;
import org.citrusframework.TestCaseRunner;
import org.citrusframework.annotations.CitrusResource;
public class MyTest implements Runnable, TestActionSupport {
@CitrusResource
TestCaseRunner t;
@Override
public void run() {
t.when(
http().client("http://localhost:8080/test")
.send()
.post()
.contentType("text/plain")
.body("Hello from Citrus!")
);
t.then(
receive().endpoint("kafka:my-topic")
.message()
.body("Hello from Citrus!")
);
t.and(
http().client("http://localhost:8080/test")
.receive()
.response(HttpStatus.OK));
}
}
As you can see the test leverages several Citrus features like sending/receiving messages with different message transports. Receiving a message always comes with an expected message content, so Citrus performs a powerful message validation on body and header content. Citrus is able to handle different message types such as XML, Json, Plaintext, YAML, CSV and more.
You can easily integrate the test into your project with one of the supported runtimes, or you can just run the test without any project setup with JBang.
citrus run MyTest.java
Still having trouble to use Citrus? Please reach out to get some help!