發(fā)布于:2021-01-21 10:47:15
0
257
0
在本文中解釋了如何使用Spring-Boot、Postgres和Docker來實現(xiàn)集成測試,以獲取Docker映像,啟動容器,使用一個或多個Docker容器運行DAOs相關(guān)測試,并在測試完成后進行處理。
集成測試的目標是驗證系統(tǒng)不同部分之間的交互是否正常工作。
考慮這個簡單的例子:
... public class ActorDaoIT { @Autowired private ActorDao actorDao; @Test public void shouldHave200Actors() { Assert.assertThat(this.actorDao.count(), Matchers.equalTo(200L)); } @Test public void shouldCreateAnActor() { Actor actor = new Actor(); actor.setFirstName("First"); actor.setLastName("Last"); actor.setLastUpdate(new Date()); Actor created = this.actorDao.save(actor); ... } ... }
此集成測試的成功運行驗證了:
在依賴項注入容器中找到類屬性actorDao。
如果存在actorDao接口的多個實現(xiàn),依賴項注入容器能夠分類使用哪一個。
與后端數(shù)據(jù)庫通信所需的憑據(jù)正確。
參與者類屬性正確映射到數(shù)據(jù)庫列名。
參與者表正好有200行。
這個微不足道的集成測試負責處理單元測試無法發(fā)現(xiàn)的可能問題。不過,這是有代價的,后端數(shù)據(jù)庫需要啟動并運行。如果集成測試使用的資源還包括消息代理或基于文本的搜索引擎,則此類服務(wù)的實例將需要正在運行且可訪問??梢钥闯?,需要額外的工作來配置和維護vm/Servers/…以便集成測試與之交互。
在本文中,我將展示并解釋如何使用springboot、Postgres和Docker實現(xiàn)集成測試,以獲取Docker映像、啟動容器、使用一個或多個Docker容器運行DAOs相關(guān)測試,并在測試完成后進行處理。
要求
Java 8或Java 7。對于Java 7,java.version版本內(nèi)部財產(chǎn)pom.xml文件需要相應(yīng)地更新。
Maven 3.3.x
熟悉Spring框架。
Docker主機,通過Docker機器或遠程主機進行本地操作。
Docker圖像
我將首先構(gòu)建兩個Docker映像,首先是一個基本Postgres Docker映像,然后是一個DVD-rental DB Docker映像,它從基本映像擴展而來,一旦容器啟動,集成測試將連接到。
基地POSTGRES DOCKER圖片
此圖像擴展了Docker hub中包含的官方Postgres圖像,并嘗試創(chuàng)建一個數(shù)據(jù)庫,將環(huán)境變量傳遞給run命令
以下是Dockerfile中的一個片段:
... ENV DB_NAME dbName ENV DB_USER dbUser ENV DB_PASSWD dbPassword RUN mkdir -p /docker-entrypoint-initdb.d ADD scripts/db-init.sh /docker-entrypoint-initdb.d/ RUN chmod 755 /docker-entrypoint-initdb.d/db-init.sh ...
在容器啟動期間,/docker entrypoint initdb.d目錄中包含的Shell或SQL文件將自動運行。這導致了db的執(zhí)行-初始化.sh地址:
#!/bin/bash echo "Verifying DB $DB_NAME presence ..." result=`psql -v ON_ERROR_STOP=on -U "$POSTGRES_USER" -d postgres -t -c "SELECT 1 FROM pg_database WHERE datname='$DB_NAME';" | xargs` if [[ $result == "1" ]]; then echo "$DB_NAME DB already exists" else echo "$DB_NAME DB does not exist, creating it ..." echo "Verifying role $DB_USER presence ..." result=`psql -v ON_ERROR_STOP=on -U "$POSTGRES_USER" -d postgres -t -c "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER';" | xargs` if [[ $result == "1" ]]; then echo "$DB_USER role already exists" else echo "$DB_USER role does not exist, creating it ..." psql -v ON_ERROR_STOP=on -U "$POSTGRES_USER" <<-EOSQL CREATE ROLE $DB_USER WITH LOGIN ENCRYPTED PASSWORD '${DB_PASSWD}'; EOSQL echo "$DB_USER role successfully created" fi psql -v ON_ERROR_STOP=on -U "$POSTGRES_USER" <<-EOSQL CREATE DATABASE $DB_NAME WITH OWNER $DB_USER TEMPLATE template0 ENCODING 'UTF8'; GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER; EOSQL result=$? if [[ $result == "0" ]]; then echo "$DB_NAME DB successfully created" else echo "$DB_NAME DB could not be created" fi fi
這個腳本主要負責創(chuàng)建Postgres角色和數(shù)據(jù)庫,并在新創(chuàng)建的用戶不存在的情況下將數(shù)據(jù)庫權(quán)限授予他們。數(shù)據(jù)庫和角色信息通過環(huán)境變量傳遞,如下所示:
docker run -d -e DB_NAME=db_dvdrental -e DB_USER=user_dvdrental -e DB_PASSWD=changeit asimio/postgres:latest
現(xiàn)在我們已經(jīng)創(chuàng)建了一個Postgres映像,其中包含用于連接到它的數(shù)據(jù)庫和角色,關(guān)于如何創(chuàng)建和設(shè)置數(shù)據(jù)庫架構(gòu),有幾個選項:
不需要其他Docker映像,因為我們已經(jīng)有了數(shù)據(jù)庫和憑據(jù),集成測試本身(在其生命周期內(nèi))將負責設(shè)置模式,假設(shè)結(jié)合使用Spring的SqlScriptsTestExecutionListener和@Sql注解。
將提供一個已經(jīng)設(shè)置了數(shù)據(jù)庫模式的映像,這意味著數(shù)據(jù)庫已經(jīng)包括表、視圖、觸發(fā)器、函數(shù)以及種子數(shù)據(jù)。
無論選擇哪個選項,我認為集成測試:
不應(yīng)強加測試執(zhí)行順序。
應(yīng)用程序外部資源應(yīng)與生產(chǎn)環(huán)境中使用的資源緊密匹配。
應(yīng)該從已知狀態(tài)開始,這意味著每個測試最好有相同的種子數(shù)據(jù),這是滿足bullet 1的結(jié)果。
這不是一個一刀切的解決方案,它應(yīng)該取決于特定的需要,例如,如果應(yīng)用程序使用的數(shù)據(jù)庫是內(nèi)存中的產(chǎn)品,那么在每個測試開始之前使用相同的容器并創(chuàng)建表可能會更快,而不是為每個測試啟動一個新的容器。
我決定使用2nd選項,用模式和種子數(shù)據(jù)設(shè)置創(chuàng)建一個Docker映像。在本例中,每個集成測試都將啟動一個新的容器,在這個容器中不需要創(chuàng)建模式,并且在容器啟動期間不需要對數(shù)據(jù)(其中可能有很多數(shù)據(jù))進行播種。下一節(jié)將介紹此選項。
DVD租賃DB POSTGRES DOCKER圖片
Pagila是從MySQL的Sakila移植的DVD租賃Postgres數(shù)據(jù)庫。它是用于運行本文中討論的集成測試的數(shù)據(jù)庫
我們來看看Dockerfile的相關(guān)命令:
... VOLUME /tmp RUN mkdir -p /tmp/data/db_dvdrental ENV DB_NAME db_dvdrental ENV DB_USER user_dvdrental ENV DB_PASSWD changeit COPY sql/dvdrental.tar /tmp/data/db_dvdrental/dvdrental.tar # Seems scripts will get executed in alphabetical-sorted order, db-init.sh needs to be executed first ADD scripts/db-restore.sh /docker-entrypoint-initdb.d/ RUN chmod 755 /docker-entrypoint-initdb.d/db-restore.sh ...
它用DB name和憑據(jù)設(shè)置環(huán)境變量,包括數(shù)據(jù)庫的轉(zhuǎn)儲和從轉(zhuǎn)儲中還原DB的腳本被復制到/docker entrypoint initdb.d目錄,正如我前面提到的,該目錄將執(zhí)行在其中找到的Shell和SQL腳本。
要從Postgres轉(zhuǎn)儲還原的腳本如下所示:
#!/bin/bash echo "Importing data into DB $DB_NAME" pg_restore -U $POSTGRES_USER -d $DB_NAME /tmp/data/db_dvdrental/dvdrental.tar echo "$DB_NAME DB restored from backup" echo "Granting permissions in DB '$DB_NAME' to role '$DB_USER'." psql -v ON_ERROR_STOP=on -U $POSTGRES_USER -d $DB_NAME <<-EOSQL GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO $DB_USER; GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO $DB_USER; EOSQL echo "Permissions granted"
注意:需要授予數(shù)據(jù)庫角色權(quán)限,否則SQL語句將無法執(zhí)行?;綪ostgres和DVD租賃映像都被設(shè)置為一旦對包含它們的存儲庫進行更改,便會自動在Docker Hub中構(gòu)建。要在本地構(gòu)建它們,請首先轉(zhuǎn)到asimio / postgres的Dockerfile所在的位置并運行:
docker build -t asimio / postgres:latest。
然后轉(zhuǎn)到找到asimio / db_dvdrental的Dockerfile的位置并運行:
docker build -t asimio / db_dvdrental:latest。
從數(shù)據(jù)庫模式生成JPA實體
我將使用maven插件來生成JPA實體,它們不包括@Idgeneration策略,但是這是一個非常好的起點,可以節(jié)省大量的時間來手動創(chuàng)建pojo。中的相關(guān)部分pom.xml文件看起來像:
... <properties> ... <postgresql.version>9.4-1206-jdbc42</postgresql.version> ... </properties> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.2</version> <configuration> <components> <component> <name>hbm2java</name> <implementation>jdbcconfiguration</implementation> <outputDirectory>target/generated-sources/hibernate3</outputDirectory> </component> </components> <componentProperties> <revengfile>src/main/resources/reveng/db_dvdrental.reveng.xml</revengfile> <propertyfile>src/main/resources/reveng/db_dvdrental.hibernate.properties</propertyfile> <packagename>com.asimio.dvdrental.model</packagename> <jdk5>true</jdk5> <ejb3>true</ejb3> </componentProperties> </configuration> <dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>${postgresql.version}</version> </dependency> </dependencies> </plugin> ...
注意:需要授予DB role權(quán)限,否則SQL語句將無法執(zhí)行?;綪ostgres和DVD租賃映像都設(shè)置為在Docker Hub中自動生成,一旦對包含它們的repos進行了更改。要在本地構(gòu)建它們,請首先轉(zhuǎn)到asimio/postgres的Dockerfile所在的位置并運行:
docker build -t asimio / postgres:latest。
然后轉(zhuǎn)到找到asimio / db_dvdrental的Dockerfile的位置并運行:
docker build -t asimio / db_dvdrental:latest。
從數(shù)據(jù)庫模式生成JPA實體
我將使用maven插件來生成JPA實體,它們不包括@Id生成策略,但是這是一個非常好的起點,可以節(jié)省大量的時間來手動創(chuàng)建pojo。中的相關(guān)部分pom.xml文件看起來像:
... <properties> ... <postgresql.version>9.4-1206-jdbc42</postgresql.version> ... </properties> ... <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>hibernate3-maven-plugin</artifactId> <version>2.2</version> <configuration> <components> <component> <name>hbm2java</name> <implementation>jdbcconfiguration</implementation> <outputDirectory>target/generated-sources/hibernate3</outputDirectory> </component> </components> <componentProperties> <revengfile>src/main/resources/reveng/db_dvdrental.reveng.xml</revengfile> <propertyfile>src/main/resources/reveng/db_dvdrental.hibernate.properties</propertyfile> <packagename>com.asimio.dvdrental.model</packagename> <jdk5>true</jdk5> <ejb3>true</ejb3> </componentProperties> </configuration> <dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>${postgresql.version}</version> </dependency> </dependencies> </plugin> ...
注意:如果使用Java 7,postgresql.version版本需要設(shè)置為9.4-1206-jdbc41。
插件配置引用db_dvdreant.reveng.xml文件,其中包括我們希望用于生成POJO的反向工程任務(wù)的模式:
... <hibernate-reverse-engineering> <schema-selection match-schema="public" /> </hibernate-reverse-engineering>
它還引用了db_dvdreent.hibernate.properties屬性其中包括要連接到要從中讀取架構(gòu)的數(shù)據(jù)庫的JDBC連接屬性:
hibernate.connection.driver_class=org.postgresql.Driver hibernate.connection.url=jdbc:postgresql://${docker.host}:5432/db_dvdrental hibernate.connection.username=user_dvdrental hibernate.connection.password=changeit
此時,我們只需要用dbu dvdrent db setup啟動一個Docker容器,并運行Maven命令來生成pojo。要啟動容器,只需運行以下命令:
docker run -d -p 5432:5432 -e DB_NAME=db_dvdrental -e DB_USER=user_dvdrental -e DB_PASSWD=changeit asimio/db_dvdrental:latest
如果在您的環(huán)境中設(shè)置了DOCKERu HOST,請按原樣運行以下Maven命令,否則執(zhí)行硬代碼docker.主機到可以找到Docker主機的IP:
mvn hibernate3:hbm2java -Ddocker.host=`echo $DOCKER_HOST | sed "s/^tcp:////" | sed "s/:.*$//"`
JPA實體應(yīng)該在target/generated sources/hibernate3生成,結(jié)果包需要復制到src/main/java
TestExecutionListener支持代碼
Spring的TestExecutionListener實現(xiàn)與集成測試生命周期掛鉤,以便在執(zhí)行之前提供Docker容器。以下是此類實現(xiàn)的一個片段:
... public class DockerizedTestExecutionListener extends AbstractTestExecutionListener { ... private DockerClient docker; private Set<String> containerIds = Sets.newConcurrentHashSet(); @Override public void beforeTestClass(TestContext testContext) throws Exception { final DockerConfig dockerConfig = (DockerConfig) TestContextUtil.getClassAnnotationConfiguration(testContext, DockerConfig.class); this.validateDockerConfig(dockerConfig); final String image = dockerConfig.image(); this.docker = this.createDockerClient(dockerConfig); LOG.debug("Pulling image '{}' from Docker registry ...", image); this.docker.pull(image); LOG.debug("Completed pulling image '{}' from Docker registry", image); if (DockerConfig.ContainerStartMode.ONCE == dockerConfig.startMode()) { this.startContainer(testContext); } super.beforeTestClass(testContext); } @Override public void prepareTestInstance(TestContext testContext) throws Exception { final DockerConfig dockerConfig = (DockerConfig) TestContextUtil.getClassAnnotationConfiguration(testContext, DockerConfig.class); if (DockerConfig.ContainerStartMode.FOR_EACH_TEST == dockerConfig.startMode()) { this.startContainer(testContext); } super.prepareTestInstance(testContext); } @Override public void afterTestClass(TestContext testContext) throws Exception { try { super.afterTestClass(testContext); for (String containerId : this.containerIds) { LOG.debug("Stopping container: {}, timeout to kill: {}", containerId, DEFAULT_STOP_WAIT_BEFORE_KILLING_CONTAINER_IN_SECONDS); this.docker.stopContainer(containerId, DEFAULT_STOP_WAIT_BEFORE_KILLING_CONTAINER_IN_SECONDS); LOG.debug("Removing container: {}", containerId); this.docker.removeContainer(containerId, RemoveContainerParam.forceKill()); } } finally { LOG.debug("Final cleanup"); IOUtils.closeQuietly(this.docker); } } ... private void startContainer(TestContext testContext) throws Exception { LOG.debug("Starting docker container in prepareTestInstance() to make System properties available to Spring context ..."); final DockerConfig dockerConfig = (DockerConfig) TestContextUtil.getClassAnnotationConfiguration(testContext, DockerConfig.class); final String image = dockerConfig.image(); // Bind container ports to automatically allocated available host ports final int[] containerToHostRandomPorts = dockerConfig.containerToHostRandomPorts(); final Map<String, List<PortBinding>> portBindings = this.bindContainerToHostRandomPorts(this.docker, containerToHostRandomPorts); // Creates container with exposed ports, makes host ports available to outside final HostConfig hostConfig = HostConfig.builder(). portBindings(portBindings). publishAllPorts(true). build(); final ContainerConfig containerConfig = ContainerConfig.builder(). hostConfig(hostConfig). image(image). build(); LOG.debug("Creating container for image: {}", image); final ContainerCreation creation = this.docker.createContainer(containerConfig); final String id = creation.id(); LOG.debug("Created container [image={}, containerId={}]", image, id); // Stores container Id to remove it for later removal this.containerIds.add(id); // Starts container this.docker.startContainer(id); LOG.debug("Started container: {}", id); Set<String> hostPorts = Sets.newHashSet(); // Sets published host ports to system properties so that test method can connect through it final ContainerInfo info = this.docker.inspectContainer(id); final Map<String, List<PortBinding>> infoPorts = info.networkSettings().ports(); for (int port : containerToHostRandomPorts) { final String hostPort = infoPorts.get(String.format("%s/tcp", port)).iterator().next().hostPort(); hostPorts.add(hostPort); final String hostToContainerPortMapPropName = String.format(HOST_PORT_SYS_PROPERTY_NAME_PATTERN, port); System.getProperties().put(hostToContainerPortMapPropName, hostPort); LOG.debug(String.format("Mapped ports host=%s to container=%s via System property=%s", hostPort, port, hostToContainerPortMapPropName)); } // Makes sure ports are LISTENing before giving running test if (dockerConfig.waitForPorts()) { LOG.debug("Waiting for host ports [{}] ...", StringUtils.join(hostPorts, ", ")); final Collection<Integer> intHostPorts = Collections2.transform(hostPorts, new Function<String, Integer>() { @Override public Integer apply(String arg) { return Integer.valueOf(arg); } } ); NetworkUtil.waitForPort(this.docker.getHost(), intHostPorts, DEFAULT_PORT_WAIT_TIMEOUT_IN_MILLIS); LOG.debug("All ports are now listening"); } } ... }
此類方法beforeTestClass()、prepareTestInstance()和afterTestClass()用于管理Docker容器的生命周期:
beforeTestClass():在第一個測試之前只執(zhí)行一次。它的目的是拉取Docker映像,并且根據(jù)測試類是否將重復使用同一個正在運行的容器,它還可能啟動一個容器。
prepareTestInstance():在運行下一個測試方法之前調(diào)用。它的目的是根據(jù)每個測試方法是否需要啟動一個新的容器,否則將重新使用在beforeTestClass()中啟動的同一個正在運行的容器。
afterTestClass():在執(zhí)行所有測試之后,只執(zhí)行一次。其目的是停止并移除正在運行的容器。
為什么我不在beforeTestMethod()和afterTestMethod()TestExecutionListener的方法中實現(xiàn)這個功能,如果從它們的名稱來判斷似乎更合適的話?這些方法的問題取決于如何將信息傳遞回Spring以加載應(yīng)用程序上下文
為了防止硬編碼從Docker容器映射到Docker主機的任何端口,我決定使用隨機端口,例如,在演示中,我使用了一個Postgres容器,該容器在內(nèi)部偵聽端口5432,但它需要映射到主機端口,以便其他應(yīng)用程序連接到數(shù)據(jù)庫,這個主機端口是隨機選擇的,并放入JVM系統(tǒng)屬性中,如第90行所示。最后可能會出現(xiàn)如下系統(tǒng)屬性:
HOST_PORT_FOR_5432=32769
這就把我們帶到了下一節(jié)。
ActorDaoIT集成測試類
ActorDao沒那么復雜,我們來看看:
... @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SpringbootITApplication.class) @TestExecutionListeners({ DockerizedTestExecutionListener.class, DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class }) @DockerConfig(image = "asimio/db_dvdrental:latest", containerToHostRandomPorts = { 5432 }, waitForPorts = true, startMode = ContainerStartMode.FOR_EACH_TEST, registry = @RegistryConfig(email="", host="", userName="", passwd="") ) @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD) @ActiveProfiles(profiles = { "test" }) public class ActorDaoIT { @Autowired private ActorDao actorDao; @Test public void shouldHave200Actors_1() { Assert.assertThat(this.actorDao.count(), Matchers.equalTo(200L)); } ... }
有趣的部分是用于配置的@TestExecutionListeners、@DockerConfig和@DirtiesContext注釋。
前面討論的DockerizedTestExecutionListener通過@DockerConfig配置,其中包含有關(guān)Docker映像、其名稱和標記的信息,它將從何處提取以及將公開的容器端口。
使用DependencyInjectionTestExecutionListener,以便注入actorDao并可供測試運行。
DirtiesContextTestExecutionListener與@DirtiesContextannotation一起使用,使Spring在中的每個測試之后重新加載應(yīng)用程序上下文類被執(zhí)行。
重新加載應(yīng)用程序上下文(如本演示中所述)的原因是,JDBC url根據(jù)上一節(jié)末尾討論的Docker主機映射容器端口而變化。讓我們看看用于構(gòu)建數(shù)據(jù)源bean的屬性文件:
--- spring: profiles: test database: driverClassName: org.postgresql.Driver datasource: url: jdbc:postgresql://${docker.host}:${HOST_PORT_FOR_5432}/db_dvdrental username: user_dvdrentals password: changeit jpa: database: POSTGRESQL generate-ddl: false
注意到主機端口為 5432占位符?DockerizedTestExecutionListener啟動Postgres DB Docker容器后,它會為u 5432添加一個名為HOSTu PORTu的系統(tǒng)屬性,并帶有一個隨機值。當springjunit運行程序加載應(yīng)用程序上下文時,它會成功地用可用的屬性值替換yaml文件中的占位符。這只是因為Docker生命周期是在DockerizedTestExecutionListener的beforeTestClass()和prepareTestInstance()中管理的,其中應(yīng)用程序上下文尚未加載,就像beforeTestMethod()一樣。
如果每次測試都使用相同的運行容器,不需要重新加載應(yīng)用程序上下文,可以刪除與DirtiesContext相關(guān)的偵聽器@DockerConfig的startMode可以設(shè)置為容器開始模式.ONCE所以Docker容器只能通過DockerizedTestExecutionListener的beforeTestClass()啟動一次。
現(xiàn)在actordaobean已經(jīng)創(chuàng)建并可用,每個單獨的集成測試都照常執(zhí)行。
yaml文件中還有另一個占位符,docker.主機將在下一節(jié)中討論。
Maven插件配置
按照命名約定,integration test使用它作為后綴命名,例如ActorDaoIT,這意味著maven surefire plugin在測試階段不會執(zhí)行它,所以改用maven failsafe plugin。來自的相關(guān)部分pom.xml文件包括:
<properties> ... <maven-failsafe-plugin.version>2.19.1</maven-failsafe-plugin.version> ... </properties> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-failsafe-plugin</artifactId> <version>${maven-failsafe-plugin.version}</version> <executions> <execution> <goals> <goal>integration-test</goal> <goal>verify</goal> </goals> </execution> </executions> </plugin> ...
從命令行運行
除了JAVAu HOME、M2u HOME、PATH環(huán)境變量之外,還有一些需要設(shè)置的變量(例如在~/.bashrc中),因為Spotify的docker客戶端在DockerizedTestExecutionListener中使用這些變量。
export DOCKER_HOST=172.16.69.133:2376 export DOCKER_MACHINE_NAME=osxdocker export DOCKER_TLS_VERIFY=1 export DOCKER_CERT_PATH=~/.docker/machine/certs
一旦找到這些變量,就可以使用以下方法構(gòu)建和測試演示:
mvn verify -Ddocker.host=`echo $DOCKER_HOST | sed "s/^tcp:////" | sed "s/:.*$//"`
docker.host作為VM參數(shù)傳遞(僅DOCKERu主機IP),并在Spring JUnit runner為每個測試創(chuàng)建應(yīng)用程序上下文時替換。
從Eclipse運行
如前一節(jié)所述,DOCKER_*環(huán)境變量和docker.主機VM參數(shù)需要傳遞給Eclipse中的測試類,實現(xiàn)這一點的方法是在“運行配置”對話框中設(shè)置它們->環(huán)境選項卡:
和運行配置對話框->參數(shù)選項卡
并運行JUnit測試通常是這樣就這樣,享受吧!我將非常感謝您的反饋,我很樂意為您解答。