Skip to content

Commit bc42e38

Browse files
committed
docs: update service stub
1 parent 9f7ce4e commit bc42e38

File tree

3 files changed

+59
-40
lines changed

3 files changed

+59
-40
lines changed

service-stub/README.md

+50-34
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,30 @@
22
title: "Service Stub Pattern in Java: Simplifying Testing with Stub Implementations"
33
shortTitle: Service Stub
44
description: "Explore the Service Stub design pattern in Java using a Sentiment Analysis example. Learn how stub implementations provide dummy services to facilitate testing and development."
5-
category: Structural
5+
category: Testing
66
language: en
77
tag:
8+
- API design
89
- Decoupling
10+
- Integration
11+
- Microservices
12+
- Testing
913
---
1014

1115
## Also known as
1216

13-
* Dummy Service
14-
* Fake Service
17+
* Service Mock
18+
* Test Double
1519

1620
## Intent of Service Stub Pattern
1721

18-
The Service Stub pattern provides a lightweight, dummy implementation of an external service to allow testing or development without relying on the real service, which may be unavailable, slow, or resource-intensive.
22+
Provide a lightweight, simplified implementation of a remote or external service to facilitate testing in isolation.
1923

2024
## Detailed Explanation of Service Stub Pattern with Real-World Example
2125

2226
Real-world example
2327

24-
> In this example, we simulate a **Sentiment Analysis Service**. The real implementation delays execution and randomly decides the sentiment. The stub implementation, on the other hand, quickly returns predefined responses based on input text ("good", "bad", or neutral), making it ideal for testing.
28+
> A real-world analogy for the Service Stub pattern could be a flight simulator used to train pilots. Instead of learning to fly directly using a real airplane—which would be costly, dangerous, and often impractical—pilots initially practice within a simulator. This simulator provides predefined, realistic scenarios and reactions, enabling pilots to train safely, repeatedly, and predictably without the complexities and risks associated with actual flight operations. Similarly, a Service Stub provides controlled, predictable responses for external services during testing, simplifying and accelerating software development and testing processes.
2529
2630
In plain words
2731

@@ -37,21 +41,24 @@ Sequence diagram
3741

3842
## Programmatic Example of Service Stub Pattern in Java
3943

40-
We define a `SentimentAnalysisService` interface and provide two implementations:
44+
We demonstrate the Service Stub pattern using a simple sentiment analysis example. To illustrate this clearly, we define a common interface `SentimentAnalysisServer` and create two separate implementations:
4145

42-
1. **RealSentimentAnalysisServer**: Simulates a slow, random sentiment analysis system.
43-
2. **StubSentimentAnalysisServer**: Returns a deterministic result based on input keywords.
46+
**RealSentimentAnalysisServer**: Represents a slow, realistic sentiment analysis service, returning random sentiment results to simulate external complexity and latency.
47+
48+
**StubSentimentAnalysisServer**: Provides fast, deterministic results based on simple keyword matching, suitable for isolated testing without external dependencies.
49+
50+
### Step-by-step Example Implementation
51+
52+
First, define a common interface that both implementations will use:
4453

45-
### Example Implementation
46-
Both the real service and the stub implement the interface below.
4754
```java
4855
public interface SentimentAnalysisServer {
4956
String analyzeSentiment(String text);
5057
}
5158
```
52-
The real sentiment analysis class returns a random response for a given input and simulates the runtime by sleeping
53-
the Thread for 5 seconds. The Supplier\<Integer\> allows injecting controlled sentiment values during testing, ensuring
54-
deterministic outputs.
59+
60+
Next, we create a realistic implementation that simulates a slow, external service. It introduces a delay of 5 seconds and returns random sentiment results (`Positive`, `Negative`, or `Neutral`). For flexibility and easier testing, it allows injecting a custom sentiment supplier:
61+
5562
```java
5663
public class RealSentimentAnalysisServer implements SentimentAnalysisServer {
5764

@@ -77,8 +84,9 @@ public class RealSentimentAnalysisServer implements SentimentAnalysisServer {
7784
}
7885
}
7986
```
80-
The stub implementation simulates the real sentiment analysis class and provides a deterministic output
81-
for a given input. Additionally, its runtime is almost zero.
87+
88+
Then, we provide a simplified stub implementation designed specifically for testing purposes. It returns immediate and predictable results based on simple keyword detection. This enables tests to run quickly and consistently without relying on external factors:
89+
8290
```java
8391
public class StubSentimentAnalysisServer implements SentimentAnalysisServer {
8492

@@ -95,9 +103,10 @@ public class StubSentimentAnalysisServer implements SentimentAnalysisServer {
95103
}
96104
}
97105
}
98-
99106
```
100-
Here is the main function of the App class (entry point to the program)
107+
108+
Finally, here's the main application logic illustrating how to use both implementations in practice. Notice the significant performance difference between the real and stub implementations:
109+
101110
```java
102111
@Slf4j
103112
public static void main(String[] args) {
@@ -116,39 +125,46 @@ Here is the main function of the App class (entry point to the program)
116125
LOGGER.info("The sentiment is: {}", sentiment);
117126
}
118127
```
119-
## When to Use the Service Stub Pattern in Java
120128

121-
Use the Service Stub pattern when:
129+
In summary, implementing a Service Stub involves creating a simplified substitute (`StubSentimentAnalysisServer`) for an actual external service (`RealSentimentAnalysisServer`). This approach allows your tests to run quickly and consistently by isolating them from external complexity and unpredictability.
130+
131+
## When to Use the Service Stub Pattern in Java
122132

123-
* Testing components that depend on external services.
124-
* The real service is slow, unreliable, or unavailable.
125-
* You need predictable, predefined responses.
126-
* Developing offline without real service access.
133+
* When testing systems with external or third-party service dependencies.
134+
* In integration tests to isolate the service being tested from network or external dependencies.
135+
* During development when the actual services are unavailable or unreliable.
136+
* To speed up tests by avoiding calls to slower external systems.
127137

128138
## Real-World Applications of Service Stub Pattern in Java
129139

130-
* Simulating APIs (payments, recommendation systems) during testing.
131-
* Bypassing external AI/ML models in tests.
132-
* Simplifying integration testing.
140+
* WireMock: Widely used in Java testing to stub HTTP-based external services.
141+
* Mockito: Allows creating lightweight stubs for dependencies in unit testing.
142+
* Spring Cloud Contract: Provides contracts and stub servers for services in microservices architectures.
133143

134144
## Benefits and Trade-offs of Service Stub Pattern
135145

136146
Benefits:
137147

138-
* Reduces dependencies.
139-
* Provides predictable behavior.
140-
* Speeds up testing.
148+
* Simplifies testing by eliminating dependencies on external systems.
149+
* Speeds up testing processes by removing latency from external network calls.
150+
* Allows consistent, repeatable, and predictable testing scenarios.
151+
* Enables parallel test execution, improving overall development productivity.
141152

142153
Trade-offs:
143154

144-
* Requires maintaining stub logic.
145-
* May not fully represent real service behavior.
155+
* Stubs need to be regularly updated to reflect changes in the actual external services.
156+
* May introduce false confidence if stubs do not accurately represent external system behavior.
157+
* Can lead to additional overhead and maintenance of stub configurations.
146158

147159
## Related Java Design Patterns
148160

149-
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
150-
* [Strategy](https://java-design-patterns.com/patterns/strategy/)
161+
* [Adapter](https://java-design-patterns.com/patterns/adapter/): Service Stub may sometimes implement Adapter interfaces to mimic external dependencies in a test environment.
162+
* Mock Object: Similar to Service Stub, but Mock Objects usually verify interactions explicitly, while Service Stubs primarily provide predefined responses without verification.
163+
* [Proxy](https://java-design-patterns.com/patterns/proxy/): Both Service Stub and Proxy introduce intermediate objects to control access or communication with actual components, though Proxy typically manages access control and communication, while Service Stub specifically aims to isolate for testing.
151164

152165
## References and Credits
153166

154-
* [Martin Fowler: Test Stubs](https://martinfowler.com/articles/mocksArentStubs.html)
167+
* [Continuous Delivery: Reliable Software Releases through Build, Test, and Deployment Automation](https://amzn.to/4bjhTSK)
168+
* [Growing Object-Oriented Software, Guided by Tests](https://amzn.to/4dGfIuk)
169+
* [Mocks Aren't Stubs (Martin Fowler)](https://martinfowler.com/articles/mocksArentStubs.html)
170+
* [xUnit Test Patterns: Refactoring Test Code](https://amzn.to/4dHGDpm)

service-stub/src/main/java/com/iluwatar/servicestub/RealSentimentAnalysisServer.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,8 @@ public class RealSentimentAnalysisServer implements SentimentAnalysisServer {
3636
* A real sentiment analysis implementation would analyze the input string using, e.g., NLP and
3737
* determine whether the sentiment is positive, negative or neutral. Here we simply choose a
3838
* random number to simulate this. The "model" may take some time to process the input and we
39-
* simulate this by delaying the execution 5 seconds.
40-
*
41-
* @param text the input string to analyze
42-
* @return sentiment classification result (Positive, Negative, or Neutral)
39+
* simulate this by delaying the execution 5 seconds. Analyzes the sentiment of the given input
40+
* string and returns the classification result (Positive, Negative, or Neutral).
4341
*/
4442
private final Supplier<Integer> sentimentSupplier;
4543

@@ -61,6 +59,11 @@ public String analyzeSentiment(String text) {
6159
} catch (InterruptedException e) {
6260
Thread.currentThread().interrupt();
6361
}
64-
return sentiment == 0 ? "Positive" : sentiment == 1 ? "Negative" : "Neutral";
62+
63+
return switch (sentiment) {
64+
case 0 -> "Positive";
65+
case 1 -> "Negative";
66+
default -> "Neutral";
67+
};
6568
}
6669
}

service-stub/src/test/java/com/iluwatar/servicestub/AppTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
import org.junit.jupiter.api.Test;
3030

31-
public class AppTest {
31+
class AppTest {
3232
@Test
3333
void shouldExecuteWithoutException() {
3434
assertDoesNotThrow(() -> App.main(new String[] {}));

0 commit comments

Comments
 (0)