0. 목차

  1. 개요
  2. 문제 상황
  3. 해결 방법: Bean 주입을 활용한 리팩토링
  4. 테스트 코드에 적용하기
  5. 결론

1. 개요

본 글에서는 비즈니스 시나리오를 검증하는 Validator의 설계 및 구현 방식에 대해 다룹니다. 여러 개의 다양한 비즈니스 시나리오들이 존재하며 앞으로도 생성될 것을 고려한 확장성이 필요한 상황에서 처음 방식과 개선된 방식을 소개합니다.

2. 문제 상황

문제의 핵심은 코드의 중복이었습니다. 동일한 기능을 하는 서로 다른 Validator들이 중복으로 존재했는데요.

비즈니스 시나리오는 다양한 시나리오가 존재할 수 있습니다. 예를 들어 "어떤 특정" 시나리오를 살펴 보면 다음과 같습니다.

이러한 시퀀스는 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;
    }

// ...