抛出 WebServerException:无法使用 Powermock 和 Springboot 启动嵌入式 Tomcat
Throw WebServerException: Unable to start embedded Tomcat using Powermock and Springboot
我正在使用 Springboot 和 junit,我想使用 Powermock 来模拟静态 class,在添加 Powermock 之后单元测试 运行s 通过 IntelliJ IDEA 很好,但是当我 运行 mvn test
在终端下,它抛出 ApplicationContextException: 无法启动 web server\n 无法启动嵌入式 Tomcat
我的基础测试class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@RunWith(PowerMockRunner.class)
@PowerMockIgnore( {"javax.management.*", "javax.net.*", "javax.crypto.*"})
@Slf4j
@ComponentScan(basePackages = {"com.rolls"})
@ActiveProfiles("test")
@Transactional
@Rollback
public class ApplicationTest {
...test
}
测试class:
@Slf4j
@PrepareForTest(ClientCache.class)
public class RuleServiceTest extends ApplicationTest {
@Mock
private IClient iClient;
@Before
public void setUp() {
PowerMockito.mockStatic(ClientCache.class);
}
...test
}
相关maven pom.xml
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<!-- mock class -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
错误运行mvn test
:
[INFO] --- maven-surefire-plugin:3.0.0-M4:test (default-test) @ dq-web ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.rolls.ApplicationTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.015 s - in com.rolls.ApplicationTest
[INFO] Running com.rolls.common.utils.DateUtilTest
[ERROR] Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 18.619 s <<< FAILURE! - in com.rolls.common.utils.DateUtilTest
[ERROR] com.rolls.common.utils.DateUtilTest.testGetFormattedDate1 Time elapsed: 0.618 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@5b6afa58]
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@5b6afa58]
Caused by: java.lang.Error: factory already defined
...
[ERROR] com.rolls.service.impl.RuleServiceTest.testListNotIn Time elapsed: 0.001 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@795c941b]
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@795c941b]
Caused by: java.lang.Error: factory already defined
似乎@RunWith(PowerMockRunner.class)
无法启动 springboot embedded tomcat,但要使用 Powermock,我需要 运行 使用它。
问题: 谁知道如何将 Powermock 与 [ 集成=36=]Springboot?
解决:我改用Mockito 3.4.6代替PowerMock
看我的伪代码如下:
我要测试的目标方法
public String paramReplace(String type) {
...code here
IClient client = ClientCache.getClient(type);
client.execute();
...code here
}
public ClientCache {
public static getClient(String type) {
...code here
return client;
}
}
public Client {
public String execute() {
...code here
return "a";
}
}
我想测试方法 paramReplace()
,在这个方法内部,我需要模拟 ClientCache.getClient()
(静态方法)和 client.execute()
.
我的测试class:
@Slf4j
public class JobParamReplaceTest extends ApplicationTest {
@Autowired
public JobParamReplace jobParamReplace;
@Mock
private IClient iClient;
@Before
public void setUp() throws Exception {
MockitoAnnotations.openMocks(this);
// PowerMockito.mockStatic(ClientCache.class);
// iClient = Mockito.mock(IClient.class);
MockedStatic<ClientCache> clientCache = Mockito.mockStatic(ClientCache.class);
clientCache.when(() -> ClientCache.getClient(Mockito.anyInt())).thenReturn(iClient);
// Mockito.when(iClient.executeQuery(Mockito.any(ISourceDTO.class), Mockito.any(SqlQueryDTO.class))).thenReturn(new ArrayList<Map<String, Object>>());
Mockito.when(iClient.executeQuery(Mockito.any(ISourceDTO.class), Mockito.any(SqlQueryDTO.class))).thenReturn(new ArrayList(1));
}
@Test
public void testParamReplace() throws Exception {
String sql_res = jobParamReplace.paramReplace("a");
Assert.assertTrue(StringUtils.isNotBlank(sql_res));
}
}
基础测试class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)
@RunWith(SpringRunner.class)
@Slf4j
@ComponentScan(basePackages = {"com.dtstack"})
@ActiveProfiles("test")
@Transactional
@Rollback
public class ApplicationTest {
}
我的 maven 依赖项:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
总结:
使用@Mock
模拟非静态方法,使用Mockito.mockStatic(ClientCache.class)
模拟静态方法
我正在使用 Springboot 和 junit,我想使用 Powermock 来模拟静态 class,在添加 Powermock 之后单元测试 运行s 通过 IntelliJ IDEA 很好,但是当我 运行 mvn test
在终端下,它抛出 ApplicationContextException: 无法启动 web server\n 无法启动嵌入式 Tomcat
我的基础测试class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@RunWith(PowerMockRunner.class)
@PowerMockIgnore( {"javax.management.*", "javax.net.*", "javax.crypto.*"})
@Slf4j
@ComponentScan(basePackages = {"com.rolls"})
@ActiveProfiles("test")
@Transactional
@Rollback
public class ApplicationTest {
...test
}
测试class:
@Slf4j
@PrepareForTest(ClientCache.class)
public class RuleServiceTest extends ApplicationTest {
@Mock
private IClient iClient;
@Before
public void setUp() {
PowerMockito.mockStatic(ClientCache.class);
}
...test
}
相关maven pom.xml
:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<!-- mock class -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
错误运行mvn test
:
[INFO] --- maven-surefire-plugin:3.0.0-M4:test (default-test) @ dq-web ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.rolls.ApplicationTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.015 s - in com.rolls.ApplicationTest
[INFO] Running com.rolls.common.utils.DateUtilTest
[ERROR] Tests run: 3, Failures: 0, Errors: 3, Skipped: 0, Time elapsed: 18.619 s <<< FAILURE! - in com.rolls.common.utils.DateUtilTest
[ERROR] com.rolls.common.utils.DateUtilTest.testGetFormattedDate1 Time elapsed: 0.618 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@5b6afa58]
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@5b6afa58]
Caused by: java.lang.Error: factory already defined
...
[ERROR] com.rolls.service.impl.RuleServiceTest.testListNotIn Time elapsed: 0.001 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
Caused by: java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@795c941b]
Caused by: org.apache.catalina.LifecycleException: Failed to initialize component [org.apache.catalina.webresources.StandardRoot@795c941b]
Caused by: java.lang.Error: factory already defined
似乎@RunWith(PowerMockRunner.class)
无法启动 springboot embedded tomcat,但要使用 Powermock,我需要 运行 使用它。
问题: 谁知道如何将 Powermock 与 [ 集成=36=]Springboot?
解决:我改用Mockito 3.4.6代替PowerMock
看我的伪代码如下:
我要测试的目标方法
public String paramReplace(String type) {
...code here
IClient client = ClientCache.getClient(type);
client.execute();
...code here
}
public ClientCache {
public static getClient(String type) {
...code here
return client;
}
}
public Client {
public String execute() {
...code here
return "a";
}
}
我想测试方法 paramReplace()
,在这个方法内部,我需要模拟 ClientCache.getClient()
(静态方法)和 client.execute()
.
我的测试class:
@Slf4j
public class JobParamReplaceTest extends ApplicationTest {
@Autowired
public JobParamReplace jobParamReplace;
@Mock
private IClient iClient;
@Before
public void setUp() throws Exception {
MockitoAnnotations.openMocks(this);
// PowerMockito.mockStatic(ClientCache.class);
// iClient = Mockito.mock(IClient.class);
MockedStatic<ClientCache> clientCache = Mockito.mockStatic(ClientCache.class);
clientCache.when(() -> ClientCache.getClient(Mockito.anyInt())).thenReturn(iClient);
// Mockito.when(iClient.executeQuery(Mockito.any(ISourceDTO.class), Mockito.any(SqlQueryDTO.class))).thenReturn(new ArrayList<Map<String, Object>>());
Mockito.when(iClient.executeQuery(Mockito.any(ISourceDTO.class), Mockito.any(SqlQueryDTO.class))).thenReturn(new ArrayList(1));
}
@Test
public void testParamReplace() throws Exception {
String sql_res = jobParamReplace.paramReplace("a");
Assert.assertTrue(StringUtils.isNotBlank(sql_res));
}
}
基础测试class:
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = WebApplication.class)
@RunWith(SpringRunner.class)
@Slf4j
@ComponentScan(basePackages = {"com.dtstack"})
@ActiveProfiles("test")
@Transactional
@Rollback
public class ApplicationTest {
}
我的 maven 依赖项:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<scope>test</scope>
</dependency>
总结:
使用@Mock
模拟非静态方法,使用Mockito.mockStatic(ClientCache.class)
模拟静态方法