|
| 1 | +--- |
| 2 | +title: "Service Stub Pattern in Java: Simplifying Testing with Stub Implementations" |
| 3 | +shortTitle: Service Stub |
| 4 | +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 |
| 6 | +language: en |
| 7 | +tag: |
| 8 | + - Testing |
| 9 | + - Decoupling |
| 10 | + - Dummy Services |
| 11 | + - Dependency Injection |
| 12 | +--- |
| 13 | + |
| 14 | +## Also known as |
| 15 | + |
| 16 | +* Dummy Service |
| 17 | +* Fake Service |
| 18 | + |
| 19 | +## Intent of Service Stub Pattern |
| 20 | + |
| 21 | +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 | + |
| 23 | +## Detailed Explanation of Service Stub Pattern with Real-World Example |
| 24 | + |
| 25 | +Real-world example |
| 26 | + |
| 27 | +> 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 | +
|
| 29 | +In plain words |
| 30 | + |
| 31 | +> Use a fake service to return predictable results without relying on external systems. |
| 32 | +
|
| 33 | +Wikipedia says |
| 34 | + |
| 35 | +> A test stub is a dummy component used during testing to isolate behavior. |
| 36 | +
|
| 37 | +## Programmatic Example of Service Stub Pattern in Java |
| 38 | + |
| 39 | +We define a `SentimentAnalysisService` interface and provide two implementations: |
| 40 | + |
| 41 | +1. **RealSentimentAnalysisServer**: Simulates a slow, random sentiment analysis system. |
| 42 | +2. **StubSentimentAnalysisServer**: Returns a deterministic result based on input keywords. |
| 43 | + |
| 44 | +### Example Implementation |
| 45 | +Both the real service and the stub implement the interface below. |
| 46 | +```java |
| 47 | +public interface SentimentAnalysisServer { |
| 48 | + String analyzeSentiment(String text); |
| 49 | +} |
| 50 | +``` |
| 51 | +The real sentiment analysis class returns a random response for a given input and simulates the runtime by sleeping |
| 52 | +the Thread for 5 seconds. The Supplier<Integer> allows injecting controlled sentiment values during testing, ensuring |
| 53 | +deterministic outputs. |
| 54 | +```java |
| 55 | +public class RealSentimentAnalysisServer implements SentimentAnalysisServer { |
| 56 | + |
| 57 | + private final Supplier<Integer> sentimentSupplier; |
| 58 | + |
| 59 | + public RealSentimentAnalysisServer(Supplier<Integer> sentimentSupplier) { |
| 60 | + this.sentimentSupplier = sentimentSupplier; |
| 61 | + } |
| 62 | + |
| 63 | + public RealSentimentAnalysisServer() { |
| 64 | + this(() -> new Random().nextInt(3)); |
| 65 | + } |
| 66 | + |
| 67 | + @Override |
| 68 | + public String analyzeSentiment(String text) { |
| 69 | + int sentiment = sentimentSupplier.get(); |
| 70 | + try { |
| 71 | + Thread.sleep(5000); |
| 72 | + } catch (InterruptedException e) { |
| 73 | + Thread.currentThread().interrupt(); |
| 74 | + } |
| 75 | + return sentiment == 0 ? "Positive" : sentiment == 1 ? "Negative" : "Neutral"; |
| 76 | + } |
| 77 | +} |
| 78 | +``` |
| 79 | +The stub implementation simulates the real sentiment analysis class and provides a deterministic output |
| 80 | +for a given input. Additionally, its runtime is almost zero. |
| 81 | +```java |
| 82 | +public class StubSentimentAnalysisServer implements SentimentAnalysisServer { |
| 83 | + |
| 84 | + @Override |
| 85 | + public String analyzeSentiment(String text) { |
| 86 | + if (text.toLowerCase().contains("good")) { |
| 87 | + return "Positive"; |
| 88 | + } |
| 89 | + else if (text.toLowerCase().contains("bad")) { |
| 90 | + return "Negative"; |
| 91 | + } |
| 92 | + else { |
| 93 | + return "Neutral"; |
| 94 | + } |
| 95 | + } |
| 96 | +} |
| 97 | + |
| 98 | +``` |
| 99 | +Here is the main function of the App class (entry point to the program) |
| 100 | +```java |
| 101 | +@Slf4j |
| 102 | + public static void main(String[] args) { |
| 103 | + LOGGER.info("Setting up the real sentiment analysis server."); |
| 104 | + RealSentimentAnalysisServer realSentimentAnalysisServer = new RealSentimentAnalysisServer(); |
| 105 | + String text = "This movie is soso"; |
| 106 | + LOGGER.info("Analyzing input: {}", text); |
| 107 | + String sentiment = realSentimentAnalysisServer.analyzeSentiment(text); |
| 108 | + LOGGER.info("The sentiment is: {}", sentiment); |
| 109 | + |
| 110 | + LOGGER.info("Setting up the stub sentiment analysis server."); |
| 111 | + StubSentimentAnalysisServer stubSentimentAnalysisServer = new StubSentimentAnalysisServer(); |
| 112 | + text = "This movie is so bad"; |
| 113 | + LOGGER.info("Analyzing input: {}", text); |
| 114 | + sentiment = stubSentimentAnalysisServer.analyzeSentiment(text); |
| 115 | + LOGGER.info("The sentiment is: {}", sentiment); |
| 116 | + } |
| 117 | +``` |
| 118 | +## When to Use the Service Stub Pattern in Java |
| 119 | + |
| 120 | +Use the Service Stub pattern when: |
| 121 | + |
| 122 | +* Testing components that depend on external services. |
| 123 | +* The real service is slow, unreliable, or unavailable. |
| 124 | +* You need predictable, predefined responses. |
| 125 | +* Developing offline without real service access. |
| 126 | + |
| 127 | +## Real-World Applications of Service Stub Pattern in Java |
| 128 | + |
| 129 | +* Simulating APIs (payments, recommendation systems) during testing. |
| 130 | +* Bypassing external AI/ML models in tests. |
| 131 | +* Simplifying integration testing. |
| 132 | + |
| 133 | +## Benefits and Trade-offs of Service Stub Pattern |
| 134 | + |
| 135 | +Benefits: |
| 136 | + |
| 137 | +* Reduces dependencies. |
| 138 | +* Provides predictable behavior. |
| 139 | +* Speeds up testing. |
| 140 | + |
| 141 | +Trade-offs: |
| 142 | + |
| 143 | +* Requires maintaining stub logic. |
| 144 | +* May not fully represent real service behavior. |
| 145 | + |
| 146 | +## Related Java Design Patterns |
| 147 | + |
| 148 | +* [Proxy](https://java-design-patterns.com/patterns/proxy/) |
| 149 | +* [Strategy](https://java-design-patterns.com/patterns/strategy/) |
| 150 | + |
| 151 | +## References and Credits |
| 152 | + |
| 153 | +* [Martin Fowler: Test Stubs](https://martinfowler.com/articles/mocksArentStubs.html) |
0 commit comments