본 글에서는 비즈니스 시나리오를 검증하는 Validator
의 설계 및 구현 방식에 대해 다룹니다. 여러 개의 다양한 비즈니스 시나리오들이 존재하며 앞으로도 생성될 것을 고려한 확장성이 필요한 상황에서 처음 방식과 개선된 방식을 소개합니다.
문제의 핵심은 코드의 중복이었습니다. 동일한 기능을 하는 서로 다른 Validator
들이 중복으로 존재했는데요.
비즈니스 시나리오는 다양한 시나리오가 존재할 수 있습니다. 예를 들어 "어떤 특정" 시나리오를 살펴 보면 다음과 같습니다.
Payload1
-> 응답 -> Payload2
-> 응답이러한 시퀀스는 TestTemplate
으로 규정됩니다.
/**
* 시나리오
*/
public class 시나리오1TestTemplate extends TestTemplate {
public 시나리오1TestTemplate()
{
super(new ScenarioAction(Payload1.class), generateActionTransitions());
}
private static Map<TestAction, Set<TestAction>> generateActionTransitions() {
Map<TestAction, Set<TestAction>> transitions = new LinkedHashMap<>();
transitions.put(new ScenarioAction(Payload1.class), Set.of(new ScenarioAction(Payload1.Response.class)));
transitions.put(new ScenarioAction(Payload2.Response.class), Set.of(new ScenarioAction(Payload2.class)));
transitions.put(new ScenarioAction(Payload3.class), Set.of(new ScenarioAction(Payload3.Response.class)));
transitions.put(new ScenarioAction(Payload1.Response.class), Set.of());
return transitions;
}
}
다른 시나리오도 있을 수 있겠지요. 이를 테면 "두번째 또 다른" 시나리오는 다음과 같은 템플릿을 갖습니다.
/**
* 시나리오 2
*/
public class 시나리오2TestTemplate extends TestTemplate {
public 시나리오2TestTemplate() {
super(new ScenarioAction(Payload2.class), generateActionTransitions());
}
private static Map<TestAction, Set<TestAction>> generateActionTransitions() {
Map<TestAction, Set<TestAction>> transitions = new LinkedHashMap<>();
transitions.put(new ScenarioAction(Payload1.class), Set.of(new ScenarioAction(Payload1.Response.class)));
transitions.put(new ScenarioAction(Payload2.Response.class), Set.of(new ScenarioAction(Payload2.class)));
...
return transitions;
}
}
Validator
는 하나의 템플릿을 받아 이를 기반으로 검증 로직을 수행하도록 구현되어 있습니다. 따라서 템플릿마다 계속해서 새로운 클래스로 Validator
를 구현해주어야 하는 문제가 발생했습니다.
다음은 Validator1
와 Validator2
를 별도로 구현한 예시입니다.
public class Validator1 implements Validator {
private TestTemplate testTemplate;
private List<LogEvent> logEvents;
private Validator nextValidator;
private ResultRecorder resultRecorder;
public Validator1(@Qualifier("시나리오1ResultRecorder") ResultRecorder resultRecorder) {
this.resultRecorder = resultRecorder;
}
@Override
public boolean supports(TestTemplate testTemplate) {
return testTemplate instanceof 시나리오1TestTemplate;
}
// ...