如何解决Maven测试模块与公共模块的循环依赖问题
解决Maven循环依赖问题:测试Mock模块与公共模块的依赖冲突
项目结构
project: ├── pom.xml │ ├── project-algo-common │ ├── pom.xml │ └── src.main.java │ └── com.company.project │ ├──── providers │ │ ├──── ProviderX.java │ │ ├──── ProviderY.java │ │ └──── ProviderZ.java │ └──── entities │ ├──── X.java │ ├──── Y.java │ └──── Z.java │ ├── project-algo-A1 │ ├── pom.xml │ ├── src.main.java │ │ └── com.company.project │ │ ├──── helpers │ │ │ ├──── HelperPPP.java │ │ │ ├──── HelperOOO.java │ │ │ └──── HelperKKK.java │ │ └──── computator │ │ └──── ComputatorA1.java │ └── src.test.java │ └── com.company.project │ └──── computator │ └──── ComputatorA1Test.java │ └── project-algo-B1 ├── pom.xml ├── src.main.java │ └── com.company.project │ ├──── helpers │ │ ├──── HelperQQQ.java │ │ ├──── HelperWWW.java │ │ └──── HelperEEE.java │ └──── computator │ └──── ComputatorB1.java └── src.test.java └── com.company.project └──── computator └──── ComputatorB1Test.java
问题场景与报错
项目中Helper类依赖project-algo-common模块的Provider类从MongoDB获取数据,单元测试时需要Mock这些Provider类,改为从CSV文件读取数据。为此创建了ProviderXMocked、ProviderYMocked、ProviderZMocked类,计划放到project-algo-unit-test模块中,作为project-algo-common的test scope依赖。但该测试模块本身需要依赖project-algo-common的主代码,导致循环依赖,报错如下:
[ERROR] The projects in the reactor contain a cyclic reference: Edge between 'Vertex{label='com.company.project:project-algo-unit-test:3.0.0-SNAPSHOT'}' and 'Vertex{label='com.company.project:project-algo-common:3.0.0-SNAPSHOT'}' introduces to cycle in the graph com.company.project:project-algo-common:3.0.0-SNAPSHOT --> com.company.project:project-algo-unit-test:3.0.0-SNAPSHOT --> com.company.project:project-algo-common:3.0.0-SNAPSHOT
解决方案
方案1:将Mock类直接放入公共模块的测试源码目录
- 无需单独创建
project-algo-unit-test模块,直接在project-algo-common的src/test/java下新建com.company.project.providers.mock包,将所有Mock类放在这里。 - 优势:彻底消除循环依赖,结构简洁,Mock类与原Provider类在同一模块的测试代码中,逻辑关联紧密。
- 注意:如果其他业务模块(如A1、B1)需要复用这些Mock类,可以通过
project-algo-common的test jar引入,需要在common模块的pom.xml中配置maven-jar-plugin打包测试代码:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <executions> <execution> <goals> <goal>test-jar</goal> </goals> </execution> </executions> </plugin>
其他模块依赖时使用:
<dependency> <groupId>com.company.project</groupId> <artifactId>project-algo-common</artifactId> <version>3.0.0-SNAPSHOT</version> <type>test-jar</type> <scope>test</scope> </dependency>
方案2:调整依赖关系,让测试模块仅被业务模块依赖
- 重构依赖方向:不让
project-algo-common依赖project-algo-unit-test,而是让业务模块(A1、B1)的test scope依赖project-algo-unit-test,同时project-algo-unit-test依赖project-algo-common的主代码(或test jar)。 - 具体步骤:
- 在
project-algo-unit-test的pom.xml中添加对project-algo-common的compile或test scope依赖。 - 在
project-algo-A1和project-algo-B1的pom.xml中,添加对project-algo-unit-test的test scope依赖。
- 在
- 优势:避免循环依赖,测试模块职责明确,仅为业务模块的测试提供Mock类支持。
方案3:使用Mock框架动态生成Mock实例,无需硬编码Mock类
- 改用Mockito等Mock框架,直接在测试代码中动态Mock Provider类,无需编写
ProviderXMocked这类硬编码的Mock类。 - 示例代码:
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import static org.mockito.Mockito.when; import java.util.List; public class HelperPPPTTest { @Mock private ProviderX providerX; private HelperPPP helperPPP; @BeforeEach void setUp() { MockitoAnnotations.openMocks(this); // 从CSV读取测试数据 List<X> mockData = CsvReader.read("x_test_data.csv"); // 设置Mock方法的返回值 when(providerX.fetchData()).thenReturn(mockData); helperPPP = new HelperPPP(providerX); } @Test void testHelperLogic() { // 执行测试逻辑验证 ... } }
- 优势:无需维护独立的Mock类,减少代码量,彻底避免模块依赖问题,同时Mock逻辑更灵活,支持多场景测试。
内容的提问来源于stack exchange,提问作者Paul Marcelin Bejan
相关产品推荐
相关产品推荐

