Arquillian Cube — это расширение Arquillian, которое можно использовать для управления контейнерами Docker из Arquillian.
С этим расширением вы можете запустить Docker- контейнер (ы), выполнить тесты Arquillian и после этого закрыть контейнер (ы).
Первое, что вам нужно сделать, это добавить зависимость Arquillian Cube. Это можно сделать, используя подход Arquillian Universe:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
<dependencyManagement> <dependencies> <dependency> <groupId>org.arquillian</groupId> <artifactId>arquillian-universe</artifactId> <version>${version.arquillian_universe}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies></dependencyManagement><dependencies> <dependency> <groupId>org.arquillian.universe</groupId> <artifactId>arquillian-junit-standalone</artifactId> <scope>test</scope> <type>pom</type> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${version.junit}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.arquillian.universe</groupId> <artifactId>arquillian-cube-docker</artifactId> <scope>test</scope> <type>pom</type> </dependency></dependencies> |
Затем у вас есть три способа определения контейнеров, которые вы хотите запустить.
Первый подход — использование формата docker-compose . Вам нужно только определить файл docker-compose, необходимый для ваших тестов, и Arquillian Cube автоматически прочитает его, запустит все контейнеры, выполнит тесты и, наконец, после этого они остановят и удалят их.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
version: '2'services: pingpong: image: jonmorehouse/ping-pong ports: - "8080:8080" networks: app_net: ipv4_address: 172.16.238.10 ipv6_address: 2001:3984:3989::10 front: back:networks: front: driver: bridge back: driver: bridge app_net: driver: bridge driver_opts: com.docker.network.enable_ipv6: "true" ipam: driver: default config: - subnet: 172.16.238.0/24 gateway: 172.16.238.1 - subnet: 2001:3984:3989::/64 gateway: 2001:3984:3989::1 |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@RunWith(Arquillian.class)public class PingPongTest { @HostIp String ip; @HostPort(containerName = "pingpong", value = 8080) int port; @Test public void should_execute_a_ping_pong() { // ... } } |
В предыдущем примере определен файл составления Docker версии 2 (его можно сохранить в корне проекта, или в src / {main, test} / docker, или в src / {main, test} / resources, и Arquillian Cube выберет автоматически), создает определенную сеть и запускает определенный контейнер службы, выполняет данный тест. и, наконец, останавливается и удаляет сеть и контейнер. Ключевым моментом здесь является то, что это происходит автоматически, вам не нужно ничего делать вручную.
Второй подход заключается в использовании шаблона объекта контейнера . Вы можете рассматривать объект- контейнер как механизм для инкапсуляции областей (данных и действий), связанных с контейнером, с которым ваш тест может взаимодействовать. В этом случае не требуется docker-compose .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
@RunWith(Arquillian.class)public class FtpClientTest { public static final String REMOTE_FILENAME = "a.txt"; @Cube FtpContainer ftpContainer; @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test public void should_upload_file_to_ftp_server() throws Exception { // Given final File file = folder.newFile(REMOTE_FILENAME); Files.write(file.toPath(), "Hello World".getBytes()); // When FtpClient ftpClient = new FtpClient(ftpContainer.getIp(), ftpContainer.getBindPort(), ftpContainer.getUsername(), ftpContainer.getPassword()); try { ftpClient.uploadFile(file, REMOTE_FILENAME, "."); } finally { ftpClient.disconnect(); } // Then final boolean filePresentInContainer = ftpContainer.isFilePresentInContainer(REMOTE_FILENAME); assertThat(filePresentInContainer, is(true)); }} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
@Cube(value = "ftp", portBinding = FtpContainer.BIND_PORT + "->21/tcp")@Image("andrewvos/docker-proftpd")@Environment(key = "USERNAME", value = FtpContainer.USERNAME)@Environment(key = "PASSWORD", value = FtpContainer.PASSWORD)public class FtpContainer { static final String USERNAME = "alex"; static final String PASSWORD = "aixa"; static final int BIND_PORT = 2121; @ArquillianResource DockerClient dockerClient; @HostIp String ip; public String getIp() { return ip; } public String getUsername() { return USERNAME; } public String getPassword() { return PASSWORD; } public int getBindPort() { return BIND_PORT; } public boolean isFilePresentInContainer(String filename) { try( final InputStream file = dockerClient.copyArchiveFromContainerCmd("ftp", "/ftp/" + filename).exec()) { return file != null; } catch (Exception e) { return false; } }} |
В этом случае вы используете аннотации, чтобы определить, как должен выглядеть контейнер. Также, поскольку вы используете объекты Java, вы можете добавить методы, которые инкапсулируют операции с самим контейнером, как в этом объекте, где операция проверки, был ли загружен файл, была добавлена в объект контейнера.
Наконец, в вашем тесте вам нужно только аннотировать его аннотацией @Cube .
Обратите внимание, что вы даже можете создать определение контейнера программно:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
@Cube(value = "pingpong", portBinding = "5000->8080/tcp")public class PingPongContainer { @HostIp String dockerHost; @HostPort(8080) private int port; @CubeDockerFile public static Archive<?> createContainer() { String dockerDescriptor = Descriptors.create(DockerDescriptor.class) .from("jonmorehouse/ping-pong") .expose(8080) .exportAsString(); return ShrinkWrap.create(GenericArchive.class) .add(new StringAsset(dockerDescriptor), "Dockerfile"); } public int getConnectionPort() { return port; } public String getDockerHost() { return this.dockerHost; }} |
В этом случае файл Dockerfile создается программным способом в объекте контейнера и используется для сборки и запуска контейнера.
Третий способ — использование объекта контейнера DSL. Этот подход позволяет избежать создания класса объекта-контейнера и использования аннотаций для его определения. Он может быть создан с использованием DSL, предоставленного для этой цели:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@RunWith(Arquillian.class)public class PingPongTest { @DockerContainer Container pingpong = Container.withContainerName("pingpong") .fromImage("jonmorehouse/ping-pong") .withPortBinding(8080) .build(); @Test public void should_return_ok_as_pong() throws IOException { String response = ping(pingpong.getIpAddress(), pingpong.getBindPort(8080)); assertThat(response).containsSequence("OK"); }} |
В этом случае подход очень похож на предыдущий, но вы используете DSL для определения контейнера.
У вас есть три способа, первый — стандартный, следующий за соглашениями о создании docker, другие могут быть использованы для определения повторно используемых частей для ваших тестов.
Вы можете прочитать больше об Arquillian Cube на http://arquillian.org/arquillian-cube/
Мы продолжаем учиться,
Alex
И ты думал, что этот дурак никогда не сможет победить? Хорошо, посмотри на меня, я возвращаюсь снова, я почувствовал вкус любви простым способом, И если тебе нужно знать, пока я все еще стою, ты просто исчезнешь ( Я все еще стою — Элтон Джон)
Музыка: https://www.youtube.com/watch?v=ZHwVBirqD2s
| Ссылка: | 3 способа использования Docker Containers для тестирования в Arquillian от нашего партнера по JCG Алекса Сото в блоге One Jar To Rule All . |