我正在为我的自动化项目使用 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();
}
}
-Dspring.profiles.active=DIT
将 Spring Profile 设置为 DEV 如何在测试中动态更新spring-properties?
Cucumber-Spring 使用 Springs 测试上下文管理器。测试上下文源自用
@CucumberContextConfiguration
注释的类。因此 @DynamicPropertySource
注释必须位于该类上。
就代码组织而言,最好有一个单独的类,没有专门用于此的钩子和步骤定义。然后,您可以将此类自动装配到您的步骤定义类中。
但这并不能完全解决你的问题。
Cucumber 在启动 sprint 上下文后调用它的 before 钩子。因此,这样您将无法及时启动容器。
如果您的测试始终需要容器,您可以考虑使用
ContextCustomizer
。请参阅如何在多个 SpringBootTest 之间重用 Testcontainers?
如果没有,您必须将
CucumberContextConfiguration
带注释的类放入同级包中,并将其显式包含到专用于使用容器运行测试的套件中。
这是 Cucumber 不幸的局限性之一。