五分鐘教程:如何在Docker當(dāng)中運(yùn)行平行測(cè)試
譯文【51CTO.com快譯】 如果想在Docker中運(yùn)行平行測(cè)試,你可能會(huì)引起容器名沖突的錯(cuò)誤,下面我們來(lái)談?wù)勅绾伪苊膺@種錯(cuò)誤。當(dāng)你在CI環(huán)境下運(yùn)行測(cè)試時(shí),有時(shí)候要運(yùn)行平行測(cè)試。這種平行程序需要使用編譯工具,如詹金斯、Gradle或者M(jìn)aven插件。
如果你在使用Docker作為應(yīng)用程序的外部測(cè)試工具(例如數(shù)據(jù)庫(kù)、郵件服務(wù)器、FTP服務(wù)器),你會(huì)發(fā)現(xiàn)一個(gè)大問(wèn)題,就是在運(yùn)行平行測(cè)試時(shí),在Docker主機(jī)里,所有文件會(huì)新建一個(gè)相同命名的容器,以至于在你開(kāi)始第二個(gè)平行測(cè)試時(shí),你會(huì)得到一個(gè)關(guān)于沖突的容器名失敗,因?yàn)镈ocker主機(jī)試圖啟動(dòng)兩個(gè)相同命名的容器,或者這兩個(gè)容器具有相同的綁定端口。
針對(duì)這個(gè)問(wèn)題,你可以這樣解決:
·你可以用一個(gè)Docker主機(jī)分別給每個(gè)文件做平行測(cè)試。
·你可以重復(fù)使用相同的Docker主機(jī)并且使用Arquillian Cube Star運(yùn)算器。
Arquillian Cube是Arquillian的一個(gè)擴(kuò)展,可以用來(lái)在你的測(cè)試中管理Docker容器。使用Arquillian Cube,你需要在計(jì)算機(jī)上運(yùn)行一個(gè)Docker保護(hù)(可以是本地的或者不是),但大多數(shù)是本地的。
Arquillian Cube提供了三種不同的方法來(lái)定義容器:
·定義一個(gè)容器組成文件
·定義一個(gè)容器對(duì)象
·使用容器對(duì)象DSL
在下面的事例中,我將向您展示如何使用Docker組成和容器對(duì)象DSL。Star運(yùn)算器可以讓你指示Arquillian Cube隨機(jī)命名Cube,并且可以調(diào)整鏈接。這樣一來(lái),在執(zhí)行平行測(cè)試時(shí),就不會(huì)因?yàn)槊Q或者綁定端口發(fā)生沖突了。
我們來(lái)看一個(gè)例子:
- plugins {
- id "io.spring.dependency-management" version "1.0.2.RELEASE"
- }
- apply plugin: 'java'
- repositories {
- mavenCentral()
- jcenter()
- }
- dependencyManagement {
- imports {
- mavenBom 'org.jboss.arquillian:arquillian-bom:1.1.13.Final'
- }
- }
- dependencies {
- testCompile 'junit:junit:4.12'
- testCompile 'org.jboss.arquillian.junit:arquillian-junit-standalone'
- testCompile 'org.arquillian.cube:arquillian-cube-docker:1.3.2'
- }
- test {
- maxParallelForks = 2
- testLogging.showStandardStreams = true
- }
- #src/test/docker/docker-compose.yml
- redis*:
- image: redis:3.0.7
- ports:
- - "6379"
- @RunWith(Arquillian.class)
- public class TestOne {
- @HostPort(containerName = "redis*", value = 6379)
- private int portBinding;
- @Test
- public void should_print_port_binding() throws InterruptedException {
- System.out.println(TestOne.class.getCanonicalName() + " - " + portBinding);
- TimeUnit.SECONDS.sleep(4);
- }
- }
你可以看到Docker-組成yml文件從一個(gè)典型的Docker-組成文件發(fā)生的重要轉(zhuǎn)變,它的名字是以星號(hào)(*)或者redis*結(jié)束的,這個(gè)名字應(yīng)該是動(dòng)態(tài)生成的。這里有三個(gè)測(cè)試,我們給大家演示***個(gè),其他兩個(gè)也大同小異。
基本上,打印控制臺(tái)綁定端口連接到服務(wù)器。最終建立一個(gè)gradle文件,執(zhí)行兩個(gè)平行試驗(yàn),所以如果你在gradle運(yùn)行測(cè)試,你會(huì)發(fā)現(xiàn)兩個(gè)測(cè)試是同時(shí)執(zhí)行的,當(dāng)一個(gè)完成的時(shí)候,另一個(gè)也執(zhí)行完畢了。然后,當(dāng)你檢查輸出時(shí),你會(huì)看到下一個(gè)輸出。
- org.superbiz.parallel.runner.TestOne STANDARD_OUT
- CubeDockerConfiguration:
- serverUri = tcp://192.168.99.100:2376
- machineName = dev
- certPath = /Users/alex/.docker/machine/machines/dev
- tlsVerify = true
- dockerServerIp = 192.168.99.100
- definitionFormat = COMPOSE
- clean = false
- removeVolumes = true
- dockerContainers = containers:
- redis_9efae4a8-fcb5-4f9e-9b1d-ab591a5c4d5a:
- alwaysPull: false
- image: redis:3.0.7
- killContainer: false
- manual: false
- portBindings: !!set {56697->6379/tcp: null}
- readonlyRootfs: false
- removeVolumes: true
- networks: {}
- org.superbiz.parallel.runner.TestThree STANDARD_OUT
- CubeDockerConfiguration:
- serverUri = tcp://192.168.99.100:2376
- machineName = dev
- certPath = /Users/alex/.docker/machine/machines/dev
- tlsVerify = true
- dockerServerIp = 192.168.99.100
- definitionFormat = COMPOSE
- clean = false
- removeVolumes = true
- dockerContainers = containers:
- redis_88ff4b81-80cc-43b3-8bbe-8638dd731d8e:
- alwaysPull: false
- image: redis:3.0.7
- killContainer: false
- manual: false
- portBindings: !!set {56261->6379/tcp: null}
- readonlyRootfs: false
- removeVolumes: true
- networks: {}
- //......
- org.superbiz.parallel.runner.TestThree > should_print_port_binding STANDARD_OUT
- org.superbiz.parallel.runner.TestOne - 56261
- org.superbiz.parallel.runner.TestOne > should_print_port_binding STANDARD_OUT
- org.superbiz.parallel.runner.TestOne - 56697
- org.superbiz.parallel.runner.TestTwo > should_print_port_binding STANDARD_OUT
- org.superbiz.parallel.runner.TestOne - 56697
正如你在日志中看到的,容器的名字不是Redis或redis*,但是redis后面跟一個(gè)UUID。此外你還可以看到,當(dāng)輸出打印時(shí),綁定端口在每個(gè)情況下都是不同的。
如果你不想用docker組成的方式,你也可以用DSL容器對(duì)象的方法以編程方式定義容器,也可以支持Star運(yùn)算器。我們來(lái)看看這種情況下的事例:
- @ClassRule
- public static ContainerDslRule redisStar =
- new ContainerDslRule("redis:3.2.6", "redis*")
- .withPortBinding(6379);
這個(gè)使用容器對(duì)象的方法是相同的,你需要Arquillian Cube1.4.0來(lái)運(yùn)行它以及容器對(duì)象?;谶@一特點(diǎn),你可以運(yùn)行任何程度的平行測(cè)試,因?yàn)锳rquillian Cube可以照顧到命名和端口綁定問(wèn)題。請(qǐng)注意,在容器之間鏈接的情況下,你依然需要運(yùn)行Star運(yùn)算器,它將在運(yùn)行時(shí)解決某些問(wèn)題。了解更多Star運(yùn)算器請(qǐng)點(diǎn)擊這里。
原文作者:Alex Soto
原文標(biāo)題:Running Parallel Tests in Docker
劉妮娜譯
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】