如何为指定Java方法编写Mockito测试用例
如何为fetchLocations()方法编写Mockito测试用例
让我一步步帮你补全这个测试用例,先拆解下你的fetchLocations()方法里的关键依赖——这些都是我们需要mock的对象:
config:提供用户名、密码、OData接口地址等配置项BasicAuthRestTemplate:发起HTTP请求的模板类(注意你原方法里是直接new的实例,这会给测试带来麻烦,后面我会讲两种处理方式)StringUtility.changeUIFieldCase():字符串格式转换工具方法map.Locations():把处理后的字符串映射为Locations对象列表的工具方法
方案1:先重构原代码(推荐,让代码更易测试)
首先,把BasicAuthRestTemplate的实例化改为依赖注入,而不是在方法内直接new,这样Mockito就能轻松mock它:
// 重构后的原方法,通过构造函数注入依赖 private final Config config; private final BasicAuthRestTemplate restTemplate; public YourService(Config config, BasicAuthRestTemplate restTemplate) { this.config = config; this.restTemplate = restTemplate; } public List<Locations> fetchLocations() { String locationsOData = restTemplate.getForObject(config.getOdataUrl() + config.getLocations(), String.class); String results = StringUtility.changeUIFieldCase(locationsOData); // 修正原代码里的变量名笔误 return map.Locations(results); }
现在可以写标准的Mockito测试了:
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class YourServiceTest { @Mock private Config config; // mock配置类 @Mock private BasicAuthRestTemplate restTemplate; // mock REST请求模板 @InjectMocks private YourService yourService; // 注入被测业务类 @Test public void fetchLocationsTest() throws Exception { // 1. 准备测试数据 List<Locations> expectedLocations = new ArrayList<>(); expectedLocations.add(new Locations("北京")); // 假设Locations有对应构造方法 String mockODataResponse = "{\"locations\": [{\"name\": \"北京\"}]}"; String processedString = "{\"locations\": [{\"Name\": \"北京\"}]}"; // 模拟格式转换后的结果 // 2. 配置mock对象的行为 // 配置config返回预设的配置值 when(config.getUsername()).thenReturn("testUser"); when(config.getPassword()).thenReturn("testPass"); when(config.getOdataUrl()).thenReturn("https://example.com/odata/"); when(config.getLocations()).thenReturn("Locations"); // 配置restTemplate返回模拟的OData响应 when(restTemplate.getForObject(eq("https://example.com/odata/Locations"), eq(String.class))) .thenReturn(mockODataResponse); // 模拟静态工具方法StringUtility.changeUIFieldCase try (var mockedUtility = Mockito.mockStatic(StringUtility.class)) { mockedUtility.when(() -> StringUtility.changeUIFieldCase(mockODataResponse)) .thenReturn(processedString); // 模拟静态工具方法map.Locations try (var mockedMap = Mockito.mockStatic(map.class)) { mockedMap.when(() -> map.Locations(processedString)) .thenReturn(expectedLocations); // 3. 调用被测方法 List<Locations> actualLocations = yourService.fetchLocations(); // 4. 验证结果和交互 assertEquals(expectedLocations, actualLocations); mockedUtility.verify(() -> StringUtility.changeUIFieldCase(mockODataResponse)); mockedMap.verify(() -> map.Locations(processedString)); } } } }
方案2:不修改原代码,用PowerMock mock构造方法
如果你暂时不能修改原代码,只能用PowerMock来mockBasicAuthRestTemplate的构造函数:
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @RunWith(PowerMockRunner.class) @PrepareForTest({YourService.class, StringUtility.class, map.class}) // 声明需要处理的类 public class YourServiceTest { @Mock private Config config; @Mock private BasicAuthRestTemplate mockRestTemplate; @Test public void fetchLocationsTest() throws Exception { // 1. 准备测试数据 List<Locations> expectedLocations = new ArrayList<>(); expectedLocations.add(new Locations("北京")); String mockODataResponse = "{\"locations\": [{\"name\": \"北京\"}]}"; String processedString = "{\"locations\": [{\"Name\": \"北京\"}]}"; // 2. 配置mock行为 // 配置config返回预设值 when(config.getUsername()).thenReturn("testUser"); when(config.getPassword()).thenReturn("testPass"); when(config.getOdataUrl()).thenReturn("https://example.com/odata/"); when(config.getLocations()).thenReturn("Locations"); // mock BasicAuthRestTemplate的构造函数,返回我们的mock实例 PowerMockito.whenNew(BasicAuthRestTemplate.class) .withArguments("testUser", "testPass") .thenReturn(mockRestTemplate); // 配置mockRestTemplate的getForObject方法 when(mockRestTemplate.getForObject(eq("https://example.com/odata/Locations"), eq(String.class))) .thenReturn(mockODataResponse); // 模拟静态工具方法 PowerMockito.mockStatic(StringUtility.class); when(StringUtility.changeUIFieldCase(mockODataResponse)).thenReturn(processedString); PowerMockito.mockStatic(map.class); when(map.Locations(processedString)).thenReturn(expectedLocations); // 3. 调用被测方法 YourService yourService = new YourService(config); // 假设构造函数传入config List<Locations> actualLocations = yourService.fetchLocations(); // 4. 验证结果和构造函数调用 assertEquals(expectedLocations, actualLocations); PowerMockito.verifyNew(BasicAuthRestTemplate.class) .withArguments("testUser", "testPass"); } }
几个关键注意点:
- 原代码里
StringUtility.changeUIFieldCase(locations)是笔误,应该改为locationsOData,否则会出现变量未定义的错误 - 如果
map是实例方法而非静态方法,只需要mockmap的实例对象,不需要使用mockStatic - 测试时要确保所有外部依赖都被正确mock,避免触发真实的HTTP请求或工具方法逻辑
内容的提问来源于stack exchange,提问作者user2717017
相关产品推荐
相关产品推荐

