Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [CPT] I can read how to write process tests #4270

Merged
merged 4 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions docs/apis-tools/testing/assertions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
id: assertions
title: Assertions
description: "Use assertions to verify the process instance state."
---

The class `CamundaAssert` is the entry point for all assertions. It is based on [AssertJ](https://github.com/assertj/assertj) and [Awaitility](http://www.awaitility.org/).

The assertions follow the style: `assertThat(object_to_test)` + expected property.

Use the assertions by adding the following static import in your test class:

```java
import static io.camunda.process.test.api.CamundaAssert.assertThat;
```

:::info Assertions are blocking
Camunda executes BPMN processes asynchronously. For testing, this means that there might be a delay between creating a process instance and reaching the expected state.

The assertions handle the asynchronous behavior and wait until the expected property is fulfilled. Only if the property is not fulfilled within the given time, the assertion fails.

By default, the assertions wait 10 seconds. If needed, you can change the time using `CamundaAssert.setAssertionTimeout(Duration.ofMinutes(1))`.
:::

## Process instance assertions

You can verify the process instance state using the creation event of the process instance.

```java
// given/when
ProcessInstanceEvent processInstance =
client.newCreateInstanceCommand().bpmnProcessId("my-process").latestVersion().send().join();
// or
ProcessInstanceResult processInstance =
client.newCreateInstanceCommand().bpmnProcessId("my-process").latestVersion().withResult().send().join();

// then
assertThat(processInstance).isActive();
```

### Process instance state

Assert that the process instance is active, completed, or terminated.

```java
assertThat(processInstance).isActive();

assertThat(processInstance).isCompleted();

assertThat(processInstance).isTerminated();
```

### Element instance state

Assert that the given BPMN elements of the process instance are active, completed, or terminated. The elements are identified by their BPMN element name.

```java
assertThat(processInstance).hasActiveElements("A", "B");

assertThat(processInstance).hasComplatedElements("A", "B");
saig0 marked this conversation as resolved.
Show resolved Hide resolved

assertThat(processInstance).hasTerminatedElements("A", "B");
```

### Process instance variables

Assert that the process instance has the given variables. Local variables of BPMN elements are ignored.

```java
assertThat(processInstance).hasVariableNames("var1", "var2");

assertThat(processInstance).hasVariable("var1", 100);

Map<String, Object> expectedVariables = //
assertThat(processInstance).hasVariables(expectedVariables);
```
249 changes: 249 additions & 0 deletions docs/apis-tools/testing/connectors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
---
id: connectors
title: Connectors
description: "Enable connectors for your process test."
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

You can run your process test with [Connectors](/components/connectors/introduction.md) to verify the integration with external systems or the configuration of the Connector tasks in your processes.

For more unit-focused tests, you don't want to run the Connectors but mock the interaction, for example, by completing Connector jobs with an expected result.

## Enable Connectors

By default, the Connectors are disabled. You need to change the runtime configuration to enable them.

<Tabs groupId="client" defaultValue="spring-sdk" queryString values={
[
{label: 'Spring SDK', value: 'spring-sdk' },
{label: 'Java client', value: 'java-client' }
]
}>

<TabItem value='spring-sdk'>

Set the following property in your `application.yml` (or `application.properties`):

```yaml
io:
camunda:
process:
test:
connectors-enabled: true
```

Or, set the property directly on your test class:

```java
@SpringBootTest(properties = {"io.camunda.process.test.connectors-enabled=true"})
@CamundaSpringProcessTest
public class MyProcessTest {
//
}
```

</TabItem>

<TabItem value='java-client'>

Register the JUnit extension in your test class with enabled Connectors:

```java
// No annotation: @CamundaProcessTest
public class MyProcessTest {

@RegisterExtension
private final CamundaProcessTestExtension extension =
new CamundaProcessTestExtension().withConnectorsEnabled(true);
}
```

</TabItem>

</Tabs>

## Connector secrets

If you use [Connectors secrets](/components/connectors/use-connectors/index.md#using-secrets) in your processes, you can define them in the test runtime.

<Tabs groupId="client" defaultValue="spring-sdk" queryString values={
[
{label: 'Spring SDK', value: 'spring-sdk' },
{label: 'Java client', value: 'java-client' }
]
}>

<TabItem value='spring-sdk'>

Add your secrets under the following property in your `application.yml` (or `application.properties`):

```yaml
io:
camunda:
process:
test:
connectors-enabled: true
connectors-secrets:
GITHUB_TOKEN: ghp_secret
SLACK_TOKEN: xoxb-secret
```

Or, set the property directly on your test class:

```java
@SpringBootTest(
properties = {
"io.camunda.process.test.connectors-enabled=true",
"io.camunda.process.test.connectors-secrets.GITHUB_TOKEN=ghp_secret",
"io.camunda.process.test.connectors-secrets.SLACK_TOKEN=xoxb-secret"
}
)
@CamundaSpringProcessTest
public class MyProcessTest {
//
}
```

</TabItem>

<TabItem value='java-client'>

Add your secrets when you register the JUnit extension:

```java
// No annotation: @CamundaProcessTest
public class MyProcessTest {

@RegisterExtension
private final CamundaProcessTestExtension extension =
new CamundaProcessTestExtension()
.withConnectorsEnabled(true)
.withConnectorsSecret("GITHUB_TOKEN", "ghp_secret")
.withConnectorsSecret("SLACK_TOKEN", "xoxb-secret");
}
```

</TabItem>

</Tabs>

## Invoke an inbound Connector

You can retrieve the URL address to invoke an inbound Connector in your test from the `CamundaProcessTestContext`.

<Tabs groupId="client" defaultValue="spring-sdk" queryString values={
[
{label: 'Spring SDK', value: 'spring-sdk' },
{label: 'Java client', value: 'java-client' }
]
}>

<TabItem value='spring-sdk'>

```java
@SpringBootTest
@CamundaSpringProcessTest
public class MyProcessTest {

@Autowired private ZeebeClient client;
@Autowired private CamundaProcessTestContext processTestContext;

@Test
void shouldInvokeConnector() {
// given: a process instance waiting at a Connector event

// when
final String inboundConnectorAddress =
processTestContext.getConnectorsAddress() + "/inbound/" + CONNECTOR_ID;
// invoke the connector address, for example, via HTTP request

// then: verify that the Connector event is completed
}
}
```

</TabItem>

<TabItem value='java-client'>

```java
@CamundaProcessTest
public class MyProcessTest {

// to be injected
private ZeebeClient client;
private CamundaProcessTestContext processTestContext;

@Test
void shouldInvokeConnector() {
// given: a process instance waiting at a Connector event

// when
final String connectorInboundAddress =
processTestContext.getConnectorsAddress() + "/inbound/" + CONNECTOR_ID;
// invoke the connector address, for example, via HTTP request

// then: verify that the Connector event is completed
}
}
```

</TabItem>

</Tabs>

:::tip
You might need to wrap the invocation of the Connector in a retry loop, for example, by using [Awaitility](http://www.awaitility.org/).

There can be a delay between verifying that the Connnectors event is active and opening the Connectors inbound subscription.
:::

## Custom connectors

If you don't use the out-of-the-box Camunda Connectors but a custom Connectors bundle, you can replace the Connectors in the test runtime.

<Tabs groupId="client" defaultValue="spring-sdk" queryString values={
[
{label: 'Spring SDK', value: 'spring-sdk' },
{label: 'Java client', value: 'java-client' }
]
}>

<TabItem value='spring-sdk'>

Set the Docker image name and version of your custom Connector bundle under the following properties in your `application.yml` (or `application.properties`):

```yaml
io:
camunda:
process:
test:
connectors-enabled: true
connectors-docker-image-name: my-org/my-connectors
connectors-docker-image-version: 1.0.0
```

</TabItem>

<TabItem value='java-client'>

Set the Docker image name and version of your custom Connector bundle when you register the JUnit extension:

```java
// No annotation: @CamundaProcessTest
public class MyProcessTest {

@RegisterExtension
private final CamundaProcessTestExtension extension =
new CamundaProcessTestExtension()
.withConnectorsEnabled(true)
.withConnectorsDockerImageName("my-org/my-connectors")
.withConnectorsDockerImageVersion("1.0.0");
}
```

</TabItem>

</Tabs>
Loading
Loading