如何更新cucumber、TestNg、springboot项目中的spring boot属性

问题描述 投票:0回答:1

我正在为我的自动化项目使用 Test-Ng、Cucumber、Spring-boot 和测试容器。

我正在尝试使用 @DynamicPropertySource 注释更新属性,但它没有按预期工作。

示例测试课程

import com.sample.PromotionsService;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import io.cucumber.java.en.Given;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.web.client.RestTemplate;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.images.PullPolicy;
import org.testng.Assert;
import org.wiremock.integrations.testcontainers.WireMockContainer;

import java.time.Duration;
import java.time.temporal.ChronoUnit;

@Slf4j
@DirtiesContext
public class PromotionTests{


    private static final Network network = Network.newNetwork();

    private static final WireMockContainer wiremockServer = new WireMockContainer("wiremock/wiremock:2.35.0")
            .withNetwork(network)
            .withNetworkAliases("mockServer")
            .withMappingFromResource("weatherMock", "MockData/weatherMock.json")
            .withMappingFromResource("locationMock", "MockData/locationMock.json");

    private static final GenericContainer springBootContainer = new GenericContainer(DockerImageName.parse("promotion-service-image"))
            .withNetwork(network);


   @Autowired
   PromotionsService promotions;

    @Autowired
    @Qualifier("defaultRestTemplate")
    RestTemplate restTemplate;

    @Before("@testContainer")
    public void setUpMockServers() {
        wiremockServer.start();

        springBootContainer.dependsOn(wiremockServer)
                .withImagePullPolicy(PullPolicy.defaultPolicy())
                .withExposedPorts(20100)
                .withEnv("weather_data_host", getMockHost())
                .withEnv("location_data_host", getMockHost())
                .withStartupTimeout(Duration.of(5, ChronoUnit.MINUTES));
        springBootContainer.start();

    }
    private static String getMockHost() {
        return String.format("http://%s:%s", "mockServer", "8080");
    }

    @DynamicPropertySource
    static void setApplicationUnderTestHost(DynamicPropertyRegistry registry) {
        registry.add("promotionService.host", () -> String.format("https://%s:%s", springBootContainer.getHost(), springBootContainer.getFirstMappedPort()));
    }

    @After("@testContainer")
    public void stopContainer() {
        wiremockServer.stop();
        springBootContainer.stop();
    }

    @Given("I am mock dependency using wiremock testcontainers")
    public void iAmMockDependencyUsingWiremockTestcontainers() {

        log.info("dataIngestion server host: {}", springBootContainer.getHost());
        log.info("dataIngestion server port: {}", springBootContainer.getFirstMappedPort());

        //should call the spring bootContainer host
        dataIngestionService.ingestData(new data());

        String url = String.format("https://%s:%s/retrieveData", springBootContainer.getHost(), springBootContainer.getFirstMappedPort());
        var response = restTemplate.getForEntity(url, Object.class);
        Assert.assertTrue(response.getStatusCode().is2xxSuccessful());

    }
}

这是我的 TestNG 黄瓜跑步者课程

import io.cucumber.spring.CucumberContextConfiguration;
import io.cucumber.testng.CucumberOptions;
import io.cucumber.testng.FeatureWrapper;
import io.cucumber.testng.PickleWrapper;
import io.cucumber.testng.TestNGCucumberRunner;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

@CucumberOptions(
        features = "src/test/resources/features/",
        glue = {"com.maps.steps"},
        plugin = {"pretty", "html:src/test/reports/TestReport.html"},
        tags = "@VD"
)
@CucumberContextConfiguration
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CucumberTestRunner extends AbstractTestNGSpringContextTests {

    private TestNGCucumberRunner testNGCucumberRunner;

    @BeforeClass(alwaysRun = true)
    public void setUpClass() {
        testNGCucumberRunner = new TestNGCucumberRunner(this.getClass());
    }

    @Test(groups = "cucumber", description = "Runs Cucumber Scenarios", dataProvider = "scenarios")
    public void runCucumberScenario(PickleWrapper pickleWrapper, FeatureWrapper featureWrapper) throws Throwable {
        testNGCucumberRunner.runScenario(pickleWrapper.getPickle());
    }

    @DataProvider(parallel = false)
    public Object[][] scenarios() {
        return testNGCucumberRunner.provideScenarios();
    }

    @AfterClass(alwaysRun = true)
    public void tearDownClass() {
        testNGCucumberRunner.finish();
    }
}
  • 当我在 IntelliJ 中运行 TestNg.xml 文件时,我通过在 VM 参数中传递
     -Dspring.profiles.active=DIT
    将 Spring Profile 设置为 DEV
  • application-DEV.yml 文件中 PromotionService.host 的值指向 DEV 端点 [https://SOME-DEV-HOST]
  • 在测试中,我正在更新 PromotionService.host 的属性,以指向作为通用容器运行的 spring-boot 应用程序的主机 [https://localhost:someRANDOMPORT]
  • 但是当我检查日志时,它仍然调用 DEV 端点,而不是本地主机。

如何在测试中动态更新spring-properties?

spring-boot cucumber testng spring-boot-test testcontainers
1个回答
0
投票

Cucumber-Spring 使用 Springs 测试上下文管理器。测试上下文源自用

@CucumberContextConfiguration
注释的类。因此
@DynamicPropertySource
注释必须位于该类上。

就代码组织而言,最好有一个单独的类,没有专门用于此的钩子和步骤定义。然后,您可以将此类自动装配到您的步骤定义类中。

但这并不能完全解决你的问题。

Cucumber 在启动 sprint 上下文后调用它的 before 钩子。因此,这样您将无法及时启动容器。

如果您的测试始终需要容器,您可以考虑使用

ContextCustomizer
。请参阅如何在多个 SpringBootTest 之间重用 Testcontainers?

如果没有,您必须将

CucumberContextConfiguration
带注释的类放入同级包中,并将其显式包含到专用于使用容器运行测试的套件中。

这是 Cucumber 不幸的局限性之一。

© www.soinside.com 2019 - 2024. All rights reserved.