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: add testcontainers-oss quickstart guides #22120

Merged
merged 6 commits into from
Mar 3, 2025
Merged
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
Prev Previous commit
Next Next commit
fix: lint about using we and more
  • Loading branch information
mdelapenya committed Feb 28, 2025
commit 7dc04c284a15a42dee33e91a0012d0f91d742853
2 changes: 1 addition & 1 deletion content/manuals/testcontainers/benefits.md
Original file line number Diff line number Diff line change
@@ -38,4 +38,4 @@ automatically after the test execution is complete by using the Ryuk sidecar con
While starting the required containers, Testcontainers attaches a set of labels to the
created resources (containers, volumes, networks etc) and Ryuk automatically performs
resource clean up by matching those labels.
This works reliably even when the test process exits abnormally (e.g. sending a SIGKILL).
This works reliably even when the test process exits abnormally (for example sending a SIGKILL).
4 changes: 2 additions & 2 deletions content/manuals/testcontainers/getting-started/_index.md
Original file line number Diff line number Diff line change
@@ -31,5 +31,5 @@ It is possible to configure Testcontainers to work for other Docker setups, such
However, these are not actively tested in the main development workflow, so not all Testcontainers features might be available
and additional manual configuration might be necessary.

If you have further questions about configuration details for your setup or whether it supports running Testcontainers-based tests,
please contact the Testcontainers team and other users from the Testcontainers community on [Slack](https://slack.testcontainers.org/).
If you have further questions about configuration details for your setup or whether it supports running Testcontainers-based tests,
contact the Testcontainers team and other users from the Testcontainers community on [Slack](https://slack.testcontainers.org/).
34 changes: 16 additions & 18 deletions content/manuals/testcontainers/getting-started/go.md
Original file line number Diff line number Diff line change
@@ -20,11 +20,11 @@

From the [Go Release Policy](https://go.dev/doc/devel/release#policy):

> Each major Go release is supported until there are two newer major releases. For example, Go 1.5 was supported until the Go 1.7 release, and Go 1.6 was supported until the Go 1.8 release. We fix critical problems, including critical security problems, in supported releases as needed by issuing minor revisions (for example, Go 1.6.1, Go 1.6.2, and so on).

Check warning on line 23 in content/manuals/testcontainers/getting-started/go.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.We] Avoid using first-person plural like 'We'. Raw Output: {"message": "[Docker.We] Avoid using first-person plural like 'We'.", "location": {"path": "content/manuals/testcontainers/getting-started/go.md", "range": {"start": {"line": 23, "column": 191}}}, "severity": "WARNING"}

_Testcontainers for Go_ is tested against those two latest Go releases, therefore we recommend using any of them.
_Testcontainers for Go_ is tested against those two latest Go releases, therefore it's recommended to use any of them.

## Step 1:Install _Testcontainers for Go_
## Step 1: Install _Testcontainers for Go_

_Testcontainers for Go_ uses [go mod](https://blog.golang.org/using-go-modules) and you can get it installed via:

@@ -66,28 +66,26 @@

* `Image` is the Docker image the container starts from.
* `ExposedPorts` lists the ports to be exposed from the container.
* `WaitingFor` is a field you can use to validate when a container is ready. It
is important to get this set because it helps to know when the container is
ready to receive any traffic. In this case, we check for the logs we know come
from Redis, telling us that it is ready to accept requests.
* `WaitingFor` is a field you can use to validate when a container is ready.
It is important to get this set because it helps to know when the container is
ready to receive any traffic. In this case, the project checks for the logs that come from Redis, mentioning that it is ready to accept requests.

When you use `ExposedPorts` you have to imagine yourself using `docker run -p
<port>`. When you do so, `dockerd` maps the selected `<port>` from inside the
<port>`. When you do so, `dockerd` maps the selected `<port>` from inside the
container to a random one available on your host.

In the previous example, we expose `6379` for `tcp` traffic to the outside. This
In the previous example, the `6379/tcp` port is exposed to the outside. This

Check warning on line 77 in content/manuals/testcontainers/getting-started/go.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.SentenceLength] Write short, concise sentences. (<=40 words) Raw Output: {"message": "[Docker.SentenceLength] Write short, concise sentences. (\u003c=40 words)", "location": {"path": "content/manuals/testcontainers/getting-started/go.md", "range": {"start": {"line": 77, "column": 73}}}, "severity": "WARNING"}
allows Redis to be reachable from your code that runs outside the container, but
it also makes parallelization possible because if you add `t.Parallel` to your
tests, and each of them starts a Redis container each of them will be exposed on a
different random port.
it also makes parallel execution possible: if you add `t.Parallel` to your
tests, and each of them starts a Redis container, then each of them will be
exposed on a different random port.

`testcontainers.GenericContainer` creates the container. In this example we are
using `Started: true`. It means that the container function will wait for the
`testcontainers.GenericContainer` creates the container. This example uses `Started: true`. It means that the container function will wait for the
container to be up and running. If you set the `Start` value to `false` it won't
start, leaving to you the decision about when to start it.

All the containers must be removed at some point, otherwise they will run until
the host is overloaded. One of the ways we have to clean up is by deferring the
the host is overloaded. You can do the clean up by deferring the
terminated function: `defer testcontainers.TerminateContainer(redisC)` which
automatically handles nil container so is safe to use even in the error case.

@@ -96,11 +94,11 @@
> Look at [features/garbage_collector](https://golang.testcontainers.org/features/garbage_collector/) to know another
> way to clean up resources.

## Step 3: Make your code talk to the container
## Step 3: Talking to the container

This is just an example, but usually Go applications that rely on Redis are
using the [redis-go](https://github.com/go-redis/redis) client. This code gets
the endpoint from the container we just started, and it configures the client.
the endpoint from the container that was started before, and it configures the client.

```go
endpoint, err := redisC.Endpoint(ctx, "")
@@ -115,7 +113,7 @@
_ = client
```

We expose only one port, so the `Endpoint` does not need a second argument set.
The container exposed only one port, so the `Endpoint` does not need a second argument set.

> [!TIP]
>
@@ -130,4 +128,4 @@

## Step 5: Want to go deeper with Redis?

You can find a more elaborated Redis example in our examples section. Please check it out [here](https://golang.testcontainers.org/modules/redis/).
You can find a more elaborated Redis example in the [Redis module docs](https://golang.testcontainers.org/modules/redis/).
94 changes: 44 additions & 50 deletions content/manuals/testcontainers/getting-started/java.md
Original file line number Diff line number Diff line change
@@ -16,8 +16,8 @@

It's easy to add Testcontainers to your project - let's walk through a quick example to see how.

Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it.
In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis.
Let's imagine you have a simple program that has a dependency on Redis, and you want to add some tests for it.
In your imaginary program, there is a `RedisBackedCache` class which stores data in Redis.

You can see an example test that could have been written for it (without using Testcontainers):

@@ -43,12 +43,12 @@
```

Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability.
This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise.
We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes.
This may work if you were sure that every developer and CI machine had Redis installed, but would fail otherwise.
You might also have problems if you attempted to run tests in parallel, such as state bleeding between tests, or port clashes.

Let's start from here, and see how to improve the test with Testcontainers:

### Step 1: Add Testcontainers as a test-scoped dependency

Check warning on line 51 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 51, "column": 5}}}, "severity": "INFO"}

First, add Testcontainers as a dependency as follows:

@@ -74,9 +74,9 @@
{{< /tab >}}
{{< /tabs >}}

### Step 2: Get Testcontainers to run a Redis container during our tests
### Step 2: Run a Redis container in the tests

Check warning on line 77 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 77, "column": 5}}}, "severity": "INFO"}

Simply add the following to the body of our test class:
Simply add the following to the body of your test class:

```java
@Rule
@@ -85,22 +85,22 @@
```

The `@Rule` annotation tells JUnit to notify this field about various events in the test lifecycle.
In this case, our rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port.
In this case, the rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port.

If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers:
If you run your test as-is, then regardless of the actual test outcome, you'll see logs showing you that Testcontainers:

* was activated before our test method ran
* discovered and quickly tested our local Docker setup
* was activated before the test method ran
* discovered and quickly tested the local Docker setup
* pulled the image if necessary
* started a new container and waited for it to be ready
* shut down and deleted the container after the test

### Step 3: Make sure our code can talk to the container
### Step 3: Make sure the code can talk to the container

Check warning on line 98 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 98, "column": 5}}}, "severity": "INFO"}

Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests.
Before Testcontainers, you might have hard-coded an address like `localhost:6379` into your tests.

Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime.
We can do this in our test `setUp` method, to set up our component under test:
You can do this in your test `setUp` method, to set up your component under test:

```java
String address = redis.getHost();
@@ -112,16 +112,14 @@

> [!TIP]
>
> Notice that we also ask Testcontainers for the container's actual address with `redis.getHost();`,
> Notice that the previous code also asks Testcontainers for the container's actual address with `redis.getHost();`,
> rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may
> not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use
> `getHost()` instead.

### Step 4: Run the tests

That's it!

Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers:
Let's look at the complete test class to see how little you had to add to get up and running with Testcontainers:

```java
public class RedisBackedCacheIntTest {
@@ -158,8 +156,8 @@

It's easy to add Testcontainers to your project - let's walk through a quick example to see how.

Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it.
In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis.
Let's imagine you have a simple program that has a dependency on Redis, and you want to add some tests for it.
In your imaginary program, there is a `RedisBackedCache` class which stores data in Redis.

You can see an example test that could have been written for it (without using Testcontainers):

@@ -185,12 +183,12 @@
```

Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability.
This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise.
We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes.
This may work if you were sure that every developer and CI machine had Redis installed, but would fail otherwise.
You might also have problems if you attempted to run tests in parallel, such as state bleeding between tests, or port clashes.

Let's start from here, and see how to improve the test with Testcontainers:

### Step 1: Add Testcontainers as a test-scoped dependency

Check warning on line 191 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 191, "column": 5}}}, "severity": "INFO"}

First, add Testcontainers as a dependency as follows:

@@ -230,9 +228,9 @@
{{< /tab >}}
{{< /tabs >}}

### Step 2: Get Testcontainers to run a Redis container during our tests
### Step 2: Get Testcontainers to run a Redis container during the tests

Check warning on line 231 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 231, "column": 5}}}, "severity": "INFO"}

First, you'll need to annotate the test class with `@Testcontainers`. Furthermore, add the following to the body of our test class:
First, you'll need to annotate the test class with `@Testcontainers`. Furthermore, add the following to the body of the test class:

```java
@Container
@@ -241,22 +239,22 @@
```

The `@Container` annotation tells JUnit to notify this field about various events in the test lifecycle.
In this case, our rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port.
In this case, the rule object is a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port.

If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers:
If you run your test as-is, then regardless of the actual test outcome, you'll see logs showing you that Testcontainers:

* was activated before our test method ran
* discovered and quickly tested our local Docker setup
* was activated before the test method ran
* discovered and quickly tested the local Docker setup
* pulled the image if necessary
* started a new container and waited for it to be ready
* shut down and deleted the container after the test

### Step 3: Make sure our code can talk to the container
### Step 3: Make sure the code can talk to the container

Check warning on line 252 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 252, "column": 5}}}, "severity": "INFO"}

Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests.
Before Testcontainers, you might have hard-coded an address like `localhost:6379` into your tests.

Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime.
We can do this in our test `setUp` method, to set up our component under test:
You can do this in your test `setUp` method, to set up your component under test:

```java
String address = redis.getHost();
@@ -268,7 +266,7 @@

> [!TIP]
>
> Notice that we also ask Testcontainers for the container's actual address with `redis.getHost();`,
> Notice that the previous code also asks Testcontainers for the container's actual address with `redis.getHost();`,
> rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may
> not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use
> `getHost()` instead.
@@ -284,9 +282,7 @@

### Step 5: Run the tests

That's it!

Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers:
Let's look at the complete test class to see how little you had to add to get up and running with Testcontainers:

```java
@Testcontainers
@@ -324,8 +320,8 @@

It's easy to add Testcontainers to your project - let's walk through a quick example to see how.

Let's imagine we have a simple program that has a dependency on Redis, and we want to add some tests for it.
In our imaginary program, there is a `RedisBackedCache` class which stores data in Redis.
Let's imagine you have a simple program that has a dependency on Redis, and you want to add some tests for it.
In your imaginary program, there is a `RedisBackedCache` class which stores data in Redis.

You can see an example test that could have been written for it (without using Testcontainers):

@@ -352,12 +348,12 @@
```

Notice that the existing test has a problem - it's relying on a local installation of Redis, which is a red flag for test reliability.
This may work if we were sure that every developer and CI machine had Redis installed, but would fail otherwise.
We might also have problems if we attempted to run tests in parallel, such as state bleeding between tests, or port clashes.
This may work if you were sure that every developer and CI machine had Redis installed, but would fail otherwise.
You might also have problems if you attempted to run tests in parallel, such as state bleeding between tests, or port clashes.

Let's start from here, and see how to improve the test with Testcontainers:

### Step 1: Add Testcontainers as a test-scoped dependency

Check warning on line 356 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 356, "column": 5}}}, "severity": "INFO"}

First, add Testcontainers as a dependency as follows:

@@ -383,7 +379,7 @@
{{< /tab >}}
{{< /tabs >}}

### Step 2: Get Testcontainers to run a Redis container during our tests
### Step 2: Get Testcontainers to run a Redis container during the tests

Check warning on line 382 in content/manuals/testcontainers/getting-started/java.md

GitHub Actions / vale

[vale] reported by reviewdog 🐶 [Docker.HeadingLength] Try to keep headings short (< 8 words). Raw Output: {"message": "[Docker.HeadingLength] Try to keep headings short (\u003c 8 words).", "location": {"path": "content/manuals/testcontainers/getting-started/java.md", "range": {"start": {"line": 382, "column": 5}}}, "severity": "INFO"}

Annotate the Spock specification class with the Testcontainers extension:

@@ -392,7 +388,7 @@
class RedisBackedCacheIntTest extends Specification {
```

And add the following field to the body of our test class:
And add the following field to the body of the test class:

```groovy
GenericContainer redis = new GenericContainer<>("redis:6-alpine")
@@ -401,20 +397,20 @@

This tells Spock to start a Testcontainers `GenericContainer`, configured to use a specific Redis image from Docker Hub, and configured to expose a port.

If we run our test as-is, then regardless of the actual test outcome, we'll see logs showing us that Testcontainers:
If you run the test as-is, then regardless of the actual test outcome, you'll see logs showing you that Testcontainers:

* was activated before our test method ran
* discovered and quickly tested our local Docker setup
* was activated before the test method ran
* discovered and quickly tested the local Docker setup
* pulled the image if necessary
* started a new container and waited for it to be ready
* shut down and deleted the container after the test

### Step 3: Make sure our code can talk to the container
### Step 3: Make sure the code can talk to the container

Before Testcontainers, we might have hardcoded an address like `localhost:6379` into our tests.
Before Testcontainers, you might have hard-coded an address like `localhost:6379` in the tests.

Testcontainers uses *randomized ports* for each container it starts, but makes it easy to obtain the actual port at runtime.
We can do this in our test `setup` method, to set up our component under test:
You can do this in your test `setup` method, to set up your component under test:

```groovy
String address = redis.host
@@ -426,16 +422,14 @@

> [!TIP]
>
> Notice that we also ask Testcontainers for the container's actual address with `redis.containerIpAddress`,
> Notice that the previous code also asks Testcontainers for the container's actual address with `redis.containerIpAddress`,
> rather than hard-coding `localhost`. `localhost` may work in some environments but not others - for example it may
> not work on your current or future CI environment. As such, **avoid hard-coding** the address, and use
> `containerIpAddress` instead.

### Step 4: Run the tests

That's it!

Let's look at our complete test class to see how little we had to add to get up and running with Testcontainers:
Let's look at the complete test class to see how little you had to add to get up and running with Testcontainers:

```groovy
@org.testcontainers.spock.Testcontainers
Loading
Oops, something went wrong.