Test Double: a Stub Rate Provider
Problem
A CurrencyConverter gets the rate from a RateProvider. In a test, the provider is a stub: it gives fixed answers and calls no real service. Commands: rate CUR VALUE (the stub now answers VALUE for CUR; a new value replaces the old one), and convert CUR AMOUNT (print AMOUNT times the rate, or no rate for CUR if the stub has no answer).
Constraints
- 1 <= commands <= 100
- VALUE and AMOUNT are whole numbers
Examples
Input
rate USD 83 convert USD 10 convert EUR 5
Output
830 no rate for EUR
Solutions
Because the converter gets its provider from outside, the test can give it a stub with fixed rates. The test needs no network, runs fast and always gives the same result.
/*
* Problem : Convert with a stub.
* Input : Command lines.
* Output : One line per convert.
* Approach: Stub provider.
* Time : O(n)
* Space : O(n)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// Step 1: The converter depends on this interface. A real provider would call a web service.
interface RateProvider {
Long rateOf(String currency);
}
// Step 2: The stub gives fixed answers that the test has set.
static class StubRateProvider implements RateProvider {
final java.util.Map<String, Long> rates = new java.util.HashMap<>();
@Override
public Long rateOf(String currency) {
return rates.get(currency);
}
}
// Step 3: The converter does the work and does not know which provider it has.
static class CurrencyConverter {
private final RateProvider provider;
CurrencyConverter(RateProvider provider) {
this.provider = provider;
}
String convert(String currency, long amount) {
Long rate = provider.rateOf(currency);
return rate == null ? "no rate for " + currency : String.valueOf(rate * amount);
}
}
// This method solves the task. It receives the input and returns the answer.
static String[] solve(String[] lines) {
StubRateProvider stub = new StubRateProvider();
CurrencyConverter converter = new CurrencyConverter(stub);
java.util.List<String> out = new java.util.ArrayList<String>();
for (String line : lines) {
String[] part = line.split(" ");
if (part[0].equals("rate")) {
stub.rates.put(part[1], Long.parseLong(part[2]));
} else {
out.add(converter.convert(part[1], Long.parseLong(part[2])));
}
}
return out.toArray(new String[0]);
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
java.util.List<String> all = new java.util.ArrayList<>();
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (!line.isEmpty()) {
all.add(line);
}
}
String[] lines = all.toArray(new String[0]);
System.out.println(String.join("\n", solve(lines)));
}
}
Hints (2)
- What does the stub replace?
- Why does the converter not create the provider itself?