如何使用 Java JUnit 和 Mockito (Spring Boot) 验证传递给静态函数的参数
How to verify arguments passed to a static function with Java JUnit and Mockito (Spring Boot)
我对所有提到的技术都不熟悉,所以这可能是一个愚蠢的问题。
我们有一个 spring 启动应用程序,我们需要通过 JDBC 写入 PostgreSQL 数据库。
因此我们需要静态DriverManager.getConnection()
方法来打开连接。
现在在我的单元测试中我不想直接调用它 class。
相反,我想检查 DriverManager.getConnection()
是否使用正确的字符串调用,因为这是我预期的可观察到的外部行为。
我使用 newConnection(ConnectionType.POSTGRESQL)
方法将此行为封装到 ConnectionFactory
中,因为我们在此应用程序中使用了多个数据库。
现在我找不到一种方法来通过 Mockito 验证是否使用正确的 String
调用了此外部依赖项,就像您可以使用实例一样:
DriverManager dm = mock(DriverManager);
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verify(dm).getConnection("theConnectionStringToBeExpected");
那么静态依赖如何实现呢?
我尝试了 Captor
方式,但这似乎只适用于像
这样的直接使用
mockStatic(DriverManager.class);
final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
// What I have to do to verify
DriverManager.getConnection("theActualConnectionString");
// What I would like to do to verify
// connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verifyStatic();
StaticService.getConnection(captor.capture());
assertEquals("theExpectedConnectionString", captor.getValue());
编辑:
这是我目前用于另一台服务器的讨厌的小解决方法...
public void driverManagerIsCorrectlyCalledForAds() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
final Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:extendedsystems:advantage://server:1337/database_name;user=user;password=password;chartype=ansi"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.ADS);
assertEquals(expectedConnection, actualConnection);
}
编辑 2:
测试Class:
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.*;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ConnectionFactory.class, DriverManager.class, DatabaseDriverInformation.class})
public class ConnectionFactoryTest {
@InjectMocks
ConnectionFactory connectionFactory;
@Mock
DatabaseDriverInformation databaseDriverInformation;
@Mock
DatabaseProperties databaseProperties;
@Mock
DatabaseProperties.Pg pg;
@Mock
DatabaseDriverLoader databaseDriverLoader;
@Before
public void setUp() {
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(ads).getServer();
doReturn(1338).when(ads).getPort();
doReturn("database_name").when(ads).getDatabasename();
doReturn("user").when(ads).getUser();
doReturn("password").when(ads).getPassword();
}
@Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:postgresql://server:1338/database_name;user=user;password=password"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.POSTGRESQL);
assertEquals(expectedConnection, actualConnection);
}
}
Class 正在测试中:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.*;
@Service()
public class ConnectionFactory {
@Autowired
private DatabaseDriverLoader databaseDriverLoader;
@Autowired
DatabaseProperties databaseProperties;
public Connection newConnection(ConnectionType connectionType) {
databaseDriverLoader.load();
final String connectionString = connectionStringFor(connectionType);
try {
return DriverManager.getConnection(connectionString);
} catch (SQLException sqlException) {
throw new RuntimeException("Couldn't connect to Server");
}
}
private String connectionStringFor(ConnectionType connectionType) {
switch (connectionType) {
case ADS:
return this.adsConnectionString();
case POSTGRESQL:
return this.pgConnectionString();
default:
throw new RuntimeException("Invalid connection Type requested!");
}
}
private String adsConnectionString() {
return new StringBuilder()
.append("jdbc:extendedsystems:advantage://")
.append(databaseProperties.getAds().getServer())
.append(":")
.append(databaseProperties.getAds().getPort())
.append("/")
.append(databaseProperties.getAds().getDatabasename())
.append(";user=")
.append(databaseProperties.getAds().getUser())
.append(";password=")
.append(databaseProperties.getAds().getPassword())
.append(";chartype=ansi")
.toString();
}
private String pgConnectionString() {
return new StringBuilder()
.append("jdbc:postgresql://")
.append(databaseProperties.getPg().getServer())
.append(":")
.append(databaseProperties.getPg().getPort())
.append("/")
.append(databaseProperties.getPg().getDatabasename())
.append("?user=")
.append(databaseProperties.getPg().getUser())
.append("&password=")
.append(databaseProperties.getPg().getPassword())
.toString();
}
}
我删除了包名、一些特定的导入和一些不必要的测试。
经过一番搜索,我发现了这个:How to verify static void method has been called with power mockito
本质上:
首先:
mockStatic(ClassWithStaticFunctionToVerify.class)
秒:
Execute the Code that will call the function you want to verify later
第三:
verifyStatic();
ClassWithStaticFunctionToVerify.functionYouWantToVerify("ParameterValueYouExpect");
在它的帮助下,我得到了以下工作正常的解决方案:
@Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
// Arrange
mockStatic(DatabaseProperties.Pg.class);
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(pg).getServer();
doReturn(1338).when(pg).getPort();
doReturn("database_name").when(pg).getDatabasename();
doReturn("user").when(pg).getUser();
doReturn("password").when(pg).getPassword();
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).loadAdsDriverClass();
doNothing().when(databaseDriverLoader).loadPgDriverClass();
when(DriverManager.getConnection(anyString())).thenReturn(expectedConnection);
// Act
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
// Assert
verifyStatic();
DriverManager.getConnection("jdbc:postgresql://server:1338/database_name?user=user&password=password");
}
我对所有提到的技术都不熟悉,所以这可能是一个愚蠢的问题。
我们有一个 spring 启动应用程序,我们需要通过 JDBC 写入 PostgreSQL 数据库。
因此我们需要静态DriverManager.getConnection()
方法来打开连接。
现在在我的单元测试中我不想直接调用它 class。
相反,我想检查 DriverManager.getConnection()
是否使用正确的字符串调用,因为这是我预期的可观察到的外部行为。
我使用 newConnection(ConnectionType.POSTGRESQL)
方法将此行为封装到 ConnectionFactory
中,因为我们在此应用程序中使用了多个数据库。
现在我找不到一种方法来通过 Mockito 验证是否使用正确的 String
调用了此外部依赖项,就像您可以使用实例一样:
DriverManager dm = mock(DriverManager);
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verify(dm).getConnection("theConnectionStringToBeExpected");
那么静态依赖如何实现呢?
我尝试了 Captor
方式,但这似乎只适用于像
mockStatic(DriverManager.class);
final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
// What I have to do to verify
DriverManager.getConnection("theActualConnectionString");
// What I would like to do to verify
// connectionFactory.newConnection(ConnectionType.POSTGRESQL);
verifyStatic();
StaticService.getConnection(captor.capture());
assertEquals("theExpectedConnectionString", captor.getValue());
编辑:
这是我目前用于另一台服务器的讨厌的小解决方法...
public void driverManagerIsCorrectlyCalledForAds() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
final Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:extendedsystems:advantage://server:1337/database_name;user=user;password=password;chartype=ansi"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.ADS);
assertEquals(expectedConnection, actualConnection);
}
编辑 2:
测试Class:
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.test.context.junit4.SpringRunner;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.powermock.api.mockito.PowerMockito.*;
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({ConnectionFactory.class, DriverManager.class, DatabaseDriverInformation.class})
public class ConnectionFactoryTest {
@InjectMocks
ConnectionFactory connectionFactory;
@Mock
DatabaseDriverInformation databaseDriverInformation;
@Mock
DatabaseProperties databaseProperties;
@Mock
DatabaseProperties.Pg pg;
@Mock
DatabaseDriverLoader databaseDriverLoader;
@Before
public void setUp() {
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(ads).getServer();
doReturn(1338).when(ads).getPort();
doReturn("database_name").when(ads).getDatabasename();
doReturn("user").when(ads).getUser();
doReturn("password").when(ads).getPassword();
}
@Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).load();
Connection expectedConnection = mock(Connection.class);
when(DriverManager.getConnection("jdbc:postgresql://server:1338/database_name;user=user;password=password"))
.thenReturn(expectedConnection);
Connection actualConnection = connectionFactory.newConnection(ConnectionType.POSTGRESQL);
assertEquals(expectedConnection, actualConnection);
}
}
Class 正在测试中:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.*;
@Service()
public class ConnectionFactory {
@Autowired
private DatabaseDriverLoader databaseDriverLoader;
@Autowired
DatabaseProperties databaseProperties;
public Connection newConnection(ConnectionType connectionType) {
databaseDriverLoader.load();
final String connectionString = connectionStringFor(connectionType);
try {
return DriverManager.getConnection(connectionString);
} catch (SQLException sqlException) {
throw new RuntimeException("Couldn't connect to Server");
}
}
private String connectionStringFor(ConnectionType connectionType) {
switch (connectionType) {
case ADS:
return this.adsConnectionString();
case POSTGRESQL:
return this.pgConnectionString();
default:
throw new RuntimeException("Invalid connection Type requested!");
}
}
private String adsConnectionString() {
return new StringBuilder()
.append("jdbc:extendedsystems:advantage://")
.append(databaseProperties.getAds().getServer())
.append(":")
.append(databaseProperties.getAds().getPort())
.append("/")
.append(databaseProperties.getAds().getDatabasename())
.append(";user=")
.append(databaseProperties.getAds().getUser())
.append(";password=")
.append(databaseProperties.getAds().getPassword())
.append(";chartype=ansi")
.toString();
}
private String pgConnectionString() {
return new StringBuilder()
.append("jdbc:postgresql://")
.append(databaseProperties.getPg().getServer())
.append(":")
.append(databaseProperties.getPg().getPort())
.append("/")
.append(databaseProperties.getPg().getDatabasename())
.append("?user=")
.append(databaseProperties.getPg().getUser())
.append("&password=")
.append(databaseProperties.getPg().getPassword())
.toString();
}
}
我删除了包名、一些特定的导入和一些不必要的测试。
经过一番搜索,我发现了这个:How to verify static void method has been called with power mockito
本质上:
首先:
mockStatic(ClassWithStaticFunctionToVerify.class)
秒:
Execute the Code that will call the function you want to verify later
第三:
verifyStatic();
ClassWithStaticFunctionToVerify.functionYouWantToVerify("ParameterValueYouExpect");
在它的帮助下,我得到了以下工作正常的解决方案:
@Test
public void driverManagerIsCorrectlyCalledForPg() throws Exception {
// Arrange
mockStatic(DatabaseProperties.Pg.class);
doReturn(pg).when(databaseProperties).getPg();
doReturn("server").when(pg).getServer();
doReturn(1338).when(pg).getPort();
doReturn("database_name").when(pg).getDatabasename();
doReturn("user").when(pg).getUser();
doReturn("password").when(pg).getPassword();
mockStatic(DriverManager.class);
doNothing().when(databaseDriverLoader).loadAdsDriverClass();
doNothing().when(databaseDriverLoader).loadPgDriverClass();
when(DriverManager.getConnection(anyString())).thenReturn(expectedConnection);
// Act
connectionFactory.newConnection(ConnectionType.POSTGRESQL);
// Assert
verifyStatic();
DriverManager.getConnection("jdbc:postgresql://server:1338/database_name?user=user&password=password");
}