도도한 개발자

[Spring] 프로덕션 코드와 테스트 코드의 프로퍼티를 분리하자 본문

Backend/Spring

[Spring] 프로덕션 코드와 테스트 코드의 프로퍼티를 분리하자

Kiara Kim 2023. 8. 1. 22:27

프로덕션 코드와 테스트 코드의 프로퍼티를 분리해야 하는 이유를 알고계신가요? 저는 저만의 방식으로 납득했는데 지금부터 그 과정을 적어보려 합니다.

 

스프링 프로젝트 개발 중 프로퍼티를 암호화하기 위한 방법으로 Jasypt를 도입했습니다.

이를 위해 @Configuration 어노테이션이 붙은 클래스에 암복호화 기능을 구현했는데, Jasypt를 적용하는 방법은 따로 정리해서 올릴 예정입니다.

 

Jasypt의 암호화 및 복호화엔 이를 위한 키(key)가 있습니다. 아주 중요하면서도 노출이 되지 않도록 조심해야 하는 친구죠.

우리의 프로젝트는 public repository에 있고, 만약 이걸 프로덕션 코드에 노출시킨다면 전 세계 모든 사람들이 확인하여 복호화 하는 위험이 생기겠죠?

 

🐾 키를 보호하자

그래서 그러한 환경변수를 따로 저장하는 application.yml 파일에 다음과 키를 적어주었습니다.

이 또한 원격 저장소에 올라가는 파일이기에 이 부분은 환경변수로 보호해줘야 합니다.

 

🐾 테스트해보자

main의 이 암호화 기능을 사용한 프로덕션 코드를 실행시키면 성공합니다. 그러면 테스트는 어떻게 될까요?

 

다음과 같이 테스트 코드를 작성했습니다.

class EncryptTest extends IntegrationTest {
    @Value("${jasypt.encryptor.password}")
    private String ENCRYPT_KEY;

    @Test
    void createEncryptor() {
        PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();

        SimpleStringPBEConfig config = new SimpleStringPBEConfig();

        config.setPassword(ENCRYPT_KEY);
        config.setAlgorithm("PBEWithMD5AndDES");
        config.setKeyObtentionIterations(1000);
        config.setPoolSize(1);
        config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
        config.setStringOutputType("base64");
        encryptor.setConfig(config);

        String plain = "This is a plain sentence";
        String encryptedText = encryptor.encrypt(plain);

        String decryptedText = encryptor.decrypt(encryptedText);
        Assertions.assertThat(decryptedText).isEqualTo(plain);
    }
}

이를 테스트하니 반갑지 않은 빨간 에러가 뜨네요.

의존성 주입을 하지 않아 해결할 수 없다고 합니다. 사실 처음엔 이 에러를 보고도 뭔 말인지 몰라 좀 많이 당황했습니다. '분명 application.yml 파일에 작성해놨는데..?' 만 반복하면서 다른 방법을 생각해보았습니다.

 

💭 main 패키지의 application.yml 처럼 test 패키지에도 프로퍼티 파일을 만들어줘야하나?

그래서 다음과 같이 application.yml 파일을 만들어 main의 환경 정보와 같이 만들었습니다.

테스트 프로퍼티니까에선 이렇게만 해도 될 것 같아서 아래와 같이 작성했었죠. (근거 없었음)

그치만 실패했습니다.

이번에도 의존성 주입 이슈가 생겼고 아깐 보지 못했던 복호화 실패 이슈가 생겼습니다.

 

이게 도대체 무슨일인고 하여 그제야 검색했더니

Bean을 찾지 못해서 그렇답니다. 아니 빈이 없긴 왜없어 너가 못찾는거 아냐? 싶었는데 그럴리 없고

객체 선언을 해줘야 했죠.

근데 이건 제가 원하는 모습이 아니었어요. 잘 알지도 못하고 아직 근거를 댈 순 없지만, 왠지 테스트 코드에 Config를 주입하고 싶지 않았습니다. 저는 단지 암호화 복호화 기능이 잘 돌아가는지만 확인하고 싶었을 뿐..

 

💭 그래서 목적이 뭐였더라?

암호화 복호화하는 기능이 궁금한 거지 키를 yml 파일에 숨겨서 가져오는 건 중요하지 않다고 판단했습니다.

 

그러고 나니 처음 블로그를 읽을 땐 눈에 안 들어왔던 다음 문장이 슬슬 눈에 보이기 시작했습니다.

“운영 환경과 개발/테스트 환경은 서로 다른 설정이 필요합니다”

 

우선 이유는 밑에서 얘기하고 과감히 테스트의 프로퍼티를 다음과 같이 임의의 키로 직접 작성하고 테스트 해봤습니다.

잘 되네요.

 

🐾 근데 왜 분리해야할까요?

결론부터 말하자면 안정성, 보안성, 유지보수성 등을 높일 수 있다고 합니다. 이 부분에 대해선 직접 겪어보면서 과정을 기록해보고 싶네요.

 

그리고 운영 환경에서는 중요한 정보를 암호화해서 보호해야 하는 반면 테스트 환경에선 암호 보호에 비교적 자유로워 테스트의 무결성과 정확성이 확보된다고 합니다.

 

여러 블로그를 읽으면서 개인적으로 판단한 이유도 함께 적어볼까 합니다.

main의 resources 패키지엔 프로퍼티(구성 정보)를 관리할 application.yml 파일과 application-.yml 파일을 함께 둘 수 있고 어플리케이션 실행 시 application.yml 파일이 가장 먼저 읽힙니다. 설정에 따라 application-.yml 파일의 내용이 오버라이드 될 수 있습니다.

 

다시 말해 테스트 프로퍼티가 오버라이드 될 수도 있다는 말은, main 패키지에 둬도 되고 test 패키지에 둬도 된다는 말인데 왜 굳이 따로 관리하는것이 권장될까요? 어차피 테스트의 대상은 main의 프로덕션 코드고 이것들은 main의 프로퍼티에 의존하고 있기 때문에 테스트에 필요한 프로퍼티도 결국 해당 main의 프로퍼티의 틀을 크게 벗어나지 않습니다.

 

하지만 위의 논리라면 테스트 코드 역시 프로덕션 코드에 의존하고 있기 때문에 main 패키지에서 함께 관리해야 하는데,

이렇게 되면 빌드 시 실제 서비스에는 필요없는 테스트 코드가 함께 패키징 됩니다. 결국 main 패키지에는 실제 서비스에 필요한 자원만 존재해야 하고, 테스트코드와 테스트 프로퍼티는 모두 test 패키지 에서 관리하는 것이 적절해보입니다.