Strategy design pattern in parameterized tests for Java

public class Pizza {
private final String type;
public Pizza(final String type) { this.type = type; }
public String getType() { return this.type; }
}
public class PizzaRequest {
private Optional<String> type = Optional.empty();
public PizzaRequest withType(final String type) {
Objects.requireNonNull(type);
this.type = Optional.of(type);
return this;
}
public Optional<String> getType() {return this.type;}
}
public class PizzaFactory {
@VisibleForTesting
static final String DEFAULT_PIZZA_TYPE = "margherita";
private String type = DEFAULT_PIZZA_TYPE;
public void setDefaultType(final String type) { this.type = type;} // "pizza business logic"
public Pizza makePizza(final PizzaRequest request) {
final String resultType = request.getType().orElse(this.type);
return new Pizza(resultType);
}
}
@Test
public void shouldCreatePizzaWithUserRequestedTypeOverFactoryOne() {
// given
final PizzaFactory pf = new PizzaFactory();
pf.setDefaultType("mushroom");
final PizzaRequest request = new PizzaRequest()
.withType("cheese");
// when
final Pizza result = pf.makePizza(request);
// then
assertThat(result.getType(), equalTo("cheese"));
}
@ParameterizedTest
@MethodSource("testParameters")
public void test(final PizzaTestConfiguration ptc) {
// given
final PizzaFactory pf = new PizzaFactory();
ptc.configurePizzaFactory(pf);
final PizzaRequest request = new PizzaRequest();
ptc.configureRequest(request);
// when
final Pizza result = pf.makePizza(request);
// then
assertThat(
result.getType(),
equalTo(ptc.expectedResultPizzaType()));
}
// Simple object carrying data how the factory and pizza 
// should be customized (if at all!), and expected result.
private static class PizzaTestConfiguration {
private final Optional<String> factoryType;
private final Optional<String> pizzaType;
private final String expected;
PizzaTestConfiguration(final String factoryType,
final String pizzaType,
final String expected) {
this.factoryType = Optional.ofNullable(factoryType);
this.pizzaType = Optional.ofNullable(pizzaType);
this.expected = Objects.requireNonNull(expected);
}
void configurePizzaFactory(final PizzaFactory pizzaFactory) {
this.factoryType.ifPresent(pizzaFactory::setDefaultType);
}
void configureRequest(final PizzaRequest pizzaRequest) {
this.pizzaType.ifPresent(pizzaRequest::withType);
}
String expectedResultPizzaType() {
return this.expected;
}
}
private static final String CHEESE = "cheese";
private static final String MUSHROOM = "mushroom";
public static List<PizzaTestConfiguration> testParameters() { // No configuration -> we should get default pizza flavour.
PizzaTestConfiguration c1 = new PizzaTestConfiguration(
null, null, PizzaFactory.DEFAULT_PIZZA_TYPE);
// Only request configured -> we should get request's flavour.
PizzaTestConfiguration c2 = new PizzaTestConfiguration(
null, CHEESE, CHEESE);
// Only factory configured -> we should get factory's flavour.
PizzaTestConfiguration c3 = new PizzaTestConfiguration(
CHEESE, null, CHEESE);
// Both request & factory configured -> request wins.
PizzaTestConfiguration c4 = new PizzaTestConfiguration(
CHEESE, MUSHROOM, MUSHROOM);
return Arrays.asList(c1, c2, c3, c4);
}
@ParameterizedTest
@MethodSource("testParameters")
public void test(final PizzaTestConfiguration ptc) {
... // then
ptc.assertResult(result);
}
// Extracting interface out of PTC might also be a good idea.
PizzaTestConfiguration c5 = new PizzaTestConfiguration(...) {
void assertResult(final Pizza pizza) {
// custom code related to toppings, soft drinks, etc.
}
};
  • org.junit.jupiter:junit-jupiter-engine (for the main engine)
  • org.junit.jupiter:junit-jupiter-params (for parameterized test support)
  • org.hamcrest:hamcrest-library (for matchers)

--

--

--

Software developer, Java mostly, C & C++ sometimes (https://www.linkedin.com/in/adam-kotwasinski/)

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Node Package Master

Closures in Scala

Embracing a hybrid cloud application strategy

Cassandra internals

ASIC Hub (Non-SSH): How to run it on Windows

String Manipulation

Open source automation — what it offers in 2021?

Create Connection Between VPC (One Region) using AWS Transit Gateway

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adam Kotwasinski

Adam Kotwasinski

Software developer, Java mostly, C & C++ sometimes (https://www.linkedin.com/in/adam-kotwasinski/)

More from Medium

maven nested modules

Why Java is platform independent

Keep it Simple: dev and test environments with docker compose and Testcontainers

Model Question Solution Java