如何在Spring Boot Selenium集成测试中同步修改服务器端数据?
解决Spring Boot Selenium测试中AppData对象同步问题
核心问题分析
你遇到的问题本质是测试类中注入的AppData实例与服务器端控制器使用的实例未关联,主要可能由以下原因导致:
- 测试中硬编码了服务器端口,连接的不是Spring Boot Test启动的嵌入式服务器实例
- AppData实现类未保证线程安全,导致测试线程修改的数据无法被服务器请求线程读取
- 手动启动了额外的服务器实例,导致测试上下文与服务器上下文分离
具体解决方案
1. 修正服务器端口,连接测试启动的实例
测试类已通过@LocalServerPort获取随机端口,但代码中硬编码了8081,这会导致浏览器连接的不是测试启动的服务器,自然无法共享同一个AppData实例。修改测试方法中的URL:
public void test() { // 正确使用随机端口连接测试服务器 WebDriver driver = new ChromeDriver(options); driver.get("http://localhost:" + port); // 现在修改ad对象,服务器端会拿到更新后的数据 ad.setCards("rigged data"); }
2. 确保AppData实现类的线程安全性
测试线程修改AppData后,服务器的请求线程需要读取最新值,因此要保证AppDataImpl的字段是线程安全的。比如给字段添加volatile修饰符,保证多线程下的可见性:
@Component public class AppDataImpl implements AppData { // 用volatile保证多线程下的可见性 private volatile String cards; @Override public void setCards(String cards) { this.cards = cards; } @Override public String getCards() { return cards; } // 其他字段和方法同理处理 }
3. 禁止手动启动额外服务器实例
测试类中已经通过@SpringBootTest自动启动嵌入式服务器,务必注释掉SpringApplication.run(Application.class)这类手动启动代码,否则会创建独立的服务器实例,导致上下文分离。
4. 验证实例一致性(可选)
可以在测试类和控制器中打印AppData实例的哈希值,确认是同一个对象:
- 测试类中添加:
System.out.println("测试类中的AppData实例:" + ad.hashCode());
- AppController构造方法中添加:
System.out.println("控制器中的AppData实例:" + ad.hashCode());
如果两个哈希值相同,说明实例是同一个,此时再检查线程安全和端口问题即可。
完整修改后的测试类示例
@DirtiesContext @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = Application.class) public class IntegrationTest { @Autowired AppData ad; @Autowired AppLogic logic; @LocalServerPort int port; private WebDriver driver; private ChromeOptions options; @BeforeEach public void setUp() { System.setProperty("webdriver.chrome.driver", "D:\\chromedriver.exe"); options = new ChromeOptions(); options.addArguments("--remote-allow-origins=*"); options.setBinary("D:\\chrome.exe"); } @Test // 注意:测试方法必须添加@Test注解才能被执行 public void testDataSync() { driver = new ChromeDriver(options); driver.get("http://localhost:" + port); // 修改AppData ad.setCards("rigged data"); System.out.println("测试类修改后的cards值:" + ad.getCards()); // 此处可执行浏览器操作触发服务器请求,验证服务器是否拿到修改后的数据 // 例如点击按钮调用接口,然后断言返回结果 } @AfterEach public void tearDown() { if (driver != null) { driver.quit(); } } }
内容的提问来源于stack exchange,提问作者UnInstaller
相关产品推荐
相关产品推荐

