本文目录导读:

- 基于接口的静态模拟(最简单)
- 使用 Mockito 框架动态模拟
- 使用 WireMock 模拟 HTTP 服务
- 使用 Testcontainers + MockServer
- 使用 Spring Cloud Contract(契约测试)
- Spring Boot 的 @Profile + @Conditional
- 使用配置化模拟
- 总结对比
在Java中实现服务仿真(Service Simulation/Stub)通常用于测试、开发阶段或模拟第三方接口不可用时的替代方案,以下是几种常见的实现思路和案例:
基于接口的静态模拟(最简单)
定义一个接口,然后创建它的模拟实现类。
示例:
// 定义服务接口
public interface PaymentService {
String processPayment(String orderId, double amount);
}
// 模拟实现
@Component
public class PaymentServiceStub implements PaymentService {
@Override
public String processPayment(String orderId, double amount) {
// 模拟延迟
try { Thread.sleep(200); } catch (InterruptedException e) {}
if (orderId.startsWith("FAIL")) {
return "FAILED: Insufficient funds";
}
return "SUCCESS: Transaction " + orderId + " completed";
}
}
使用:
@Service
public class OrderService {
private final PaymentService paymentService;
public OrderService(@Qualifier("paymentServiceStub") PaymentService paymentService) {
this.paymentService = paymentService;
}
public void placeOrder() {
String result = paymentService.processPayment("ORD123", 99.99);
// 处理结果
}
}
使用 Mockito 框架动态模拟
适合单元测试,可以灵活定义行为。
@Test
public void testOrderServiceWithMock() {
// 创建 Mock
PaymentService mockService = Mockito.mock(PaymentService.class);
// 定义行为
Mockito.when(mockService.processPayment("ORD001", 100.0))
.thenReturn("SUCCESS");
Mockito.when(mockService.processPayment("ORD002", 100.0))
.thenThrow(new RuntimeException("Service unavailable"));
// 注入并使用
OrderService orderService = new OrderService(mockService);
// 进行测试断言
}
使用 WireMock 模拟 HTTP 服务
适合模拟 REST API 等远程服务。
Maven 依赖:
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-jre8</artifactId>
<version>2.35.0</version>
<scope>test</scope>
</dependency>
示例代码:
@BeforeEach
public void setup() {
WireMockServer wireMockServer = new WireMockServer(8089);
wireMockServer.start();
// 模拟一个 REST 端点
stubFor(get(urlEqualTo("/api/payment/verify"))
.withHeader("Authorization", equalTo("Bearer token123"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "application/json")
.withBody("{\"status\":\"approved\",\"transactionId\":\"TXN001\"}")
.withFixedDelay(500) // 模拟延迟
));
// 模拟错误场景
stubFor(post(urlEqualTo("/api/payment/charge"))
.withRequestBody(containing("amount\":-1"))
.willReturn(aResponse()
.withStatus(400)
.withBody("{\"error\":\"Invalid amount\"}")
));
}
@Test
public void testPaymentApi() {
// 让待测服务调用 localhost:8089 的模拟服务
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
"http://localhost:8089/api/payment/verify",
HttpMethod.GET,
new HttpEntity<>(createHeaders()),
String.class
);
assertEquals(200, response.getStatusCodeValue());
}
使用 Testcontainers + MockServer
适合更复杂的模拟场景(如数据库、消息队列等)。
依赖:
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mock-server</groupId>
<artifactId>mockserver-netty</artifactId>
<version>5.14.0</version>
<scope>test</scope>
</dependency>
示例:
@Container
public static GenericContainer<?> mockServer = new GenericContainer<>("mockserver/mockserver:5.14.0")
.withExposedPorts(1080);
@BeforeEach
public void setupMockExpectations() {
MockServerClient client = new MockServerClient(
mockServer.getHost(),
mockServer.getFirstMappedPort()
);
client.when(
request()
.withMethod("POST")
.withPath("/api/v1/process")
.withBody(json("{\"type\":\"order\"}"))
).respond(
response()
.withStatusCode(202)
.withHeader("Location", "/api/v1/status/123")
.withDelay(TimeUnit.MILLISECONDS, 100)
);
}
使用 Spring Cloud Contract(契约测试)
适合微服务间的API契约验证。
流程:
- 定义契约(Groovy/YAML)
- 自动生成Stub JAR
- 消费者使用Stub进行测试
契约示例 (groovy):
Contract.make {
description "模拟支付成功"
request {
method 'POST'
url '/api/payment'
headers {
contentType('application/json')
}
body([
orderId: $(anyUuid()),
amount: $(anyDouble())
])
}
response {
status 200
headers {
contentType('application/json')
}
body([
transactionId: $(anyUuid()),
status: 'SUCCESS'
])
}
}
Spring Boot 的 @Profile + @Conditional
通过配置切换真实/模拟服务。
// 真实实现
@Component
@Profile("!stub")
public class RealPaymentService implements PaymentService {
@Override
public String processPayment(String orderId, double amount) {
// 调用真实第三方API
}
}
// 模拟实现
@Component
@Profile("stub")
public class StubPaymentService implements PaymentService {
@Override
public String processPayment(String orderId, double amount) {
// 返回预设数据
}
}
启动时指定:
java -jar app.jar --spring.profiles.active=stub
使用配置化模拟
从外部配置文件读取模拟响应,方便测试不同场景。
application-stub.yml:
stub:
payment-service:
delay-ms: 200
responses:
"ORD001": "SUCCESS: Order completed"
"ORD002": "FAILED: Timeout"
"ORD*": "SUCCESS: Default success"
@Component
@Profile("stub")
public class ConfigurableStubPaymentService implements PaymentService {
@Value("${stub.payment-service.responses}")
private Map<String, String> responses;
@Value("${stub.payment-service.delay-ms:0}")
private int delayMs;
@Override
public String processPayment(String orderId, double amount) {
applyDelay();
return responses.entrySet().stream()
.filter(e -> orderId.matches(e.getKey().replace("*", ".*")))
.findFirst()
.map(Map.Entry::getValue)
.orElse("SUCCESS: Default response");
}
}
总结对比
| 方法 | 适合场景 | 复杂度 | 灵活性 |
|---|---|---|---|
| 静态Stub类 | 简单场景、快速验证 | 低 | 低 |
| Mockito | 单元测试 | 低 | 高 |
| WireMock | HTTP API模拟 | 中 | 高 |
| MockServer | 微服务、消息 | 中高 | 高 |
| Spring Cloud Contract | 契约测试 | 高 | 高 |
| Profile切换 | 开发/测试环境隔离 | 低 | 中 |
| 配置化模拟 | 多场景测试 | 中 | 高 |
建议:
- 单元测试:使用 Mockito + 静态Stub
- 集成测试:使用 WireMock 或 MockServer
- 多环境切换:使用 Profile + 配置化模拟
- 微服务契约:使用 Spring Cloud Contract
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播