프로그래밍/서버 프로그래밍

Spring boot S3 Local에서 Test하기

9/3 2019. 4. 4. 19:19

Spring boot S3 Local에서 Test하기

문제

S3를 사용하여 정적 이미지를 업로드 하도록 설정을 하였더니 , 문제가 생겼다. 테스트할 때 마다 실제 s3 저장소에 이미지가 올라간다는 점과, Travis 에서 빌드할 때 accessKey 와 secretKey가 없으니 계속해서 빌드에 실패하는 것이다.

해결방안

인터넷에 어떤 블로그에서 실제 회사에서 업무 시 하나의 s3 버킷에 여러명의 개발자가 붙어서 개발하면 다양한 문제가 발생할 수 있기 때문에 로컬에서 테스트시에는 s3 mock을 이용해서 로컬에서 각각의 mock으로 작성된 s3 버킷에서 테스트를 한다는 글을 며칠전에 봤던 것이 기억나는데 아무리 다시 찾아서 읽어보려해도 찾지 못했다…ㅠㅠ

그래도 그 후 s3 mock 에 관련되서 검색해본 결과 adobe에서 만든 S3MockfindifyS3 mock library for Java/Scala 가 존재하는 것을 확인하여서 프로젝트에 적용하여 봤다.


S3Mock

S3Mock


S3 Mock library for Java/Scala

S3 Mock library for Java/Scala


먼저 adobe의 S3Mock이 더 최근까지 관리되고 있는 것을 확인하여 S3Mock을 프로젝트에 적용하였다.

사이트의 README를 보면서 하나하나 적용하였는데, 중간에 계속 어딘가에서 NullPointException이 발생하는 바람에 결국 사용을 포기하고, S3 Mock library를 적용하였다.

//pom.xml
    <dependency>
        <groupId>io.findify</groupId>
        <artifactId>s3mock_2.12</artifactId>
        <version>0.2.5</version>
        <scope>test</scope>
    </dependency>

pom.xml에 dependency를 추가해주었다. ( 링크의 사이트의 예제는 0.2.4로 적혀있는데 0.2.5버전이 존재하므로 0.2.5를 사용해주자. )

이 후 S3MockConfig라는 TestConfiguration을 작성하여 주었다.

@TestConfiguration
public class S3MockConfig {

//@Value는 Properties에서 값을 가져온다.
    @Value("${cloud.aws.region.static}")
    String region;

    @Value("${cloud.aws.s3.bucket}")
    String bucket;

//S3Mock을 빌드할때 포트나 메모리에 저장할 지 실제로 저장할 지 같은 것 등등을 설정 가능하다.
    @Bean
    public S3Mock s3Mock() {
        return new S3Mock.Builder().withPort(8001).withInMemoryBackend().build();
    }

//위에서 작성한 S3Mock을 주입받는 Bean을 작성하였다.
//실제 테스트가 아닌 환경을 위해 작성된 Config환경과 같이 켜질 경우를 대비하여 @Primary를 넣어주었다.
//s3Mock.start를 이용하여 Mock S3 서버를 로컬에서 시작한다.
    @Bean
    @Primary
    public AmazonS3 amazonS3(S3Mock s3Mock){
        s3Mock.start();
        AwsClientBuilder.EndpointConfiguration endpoint = new AwsClientBuilder.EndpointConfiguration("http://localhost:8001", region);
        AmazonS3 client = AmazonS3ClientBuilder
                .standard()
                .withPathStyleAccessEnabled(true)
                .withEndpointConfiguration(endpoint)
                .withCredentials(new AWSStaticCredentialsProvider(new AnonymousAWSCredentials()))
                .build();
        client.createBucket(bucket);

        return client;
    }
}

이렇게 작성하여서 AmazonS3라는 bean을 작성하여 준 뒤, 테스트 코드를 작성하였다.

테스트 코드는 S3ImageUploader라는 클래스가 실제로 잘 작동하는 지를 테스트한다.

@SpringBootTest
@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@Import(S3MockConfig.class)
public class S3ImageUploaderTest {

    @Autowired
    S3ImageUploader s3ImageUploader;
    @Autowired
    S3Mock s3Mock;

    @Test
    public void test() throws IOException {
        String expected = "mock1.png";
        MockMultipartFile mockMultipartFile = new MockMultipartFile("file", expected,
                "image/png", "test data".getBytes());
        UploadedImageDto uploadedImageDto = s3ImageUploader.upload(mockMultipartFile, "static");

        assertThat(uploadedImageDto.getImageExtension()).isEqualTo("png");
        assertThat(uploadedImageDto.getOriginalName()).isEqualTo(expected);
    }

    @After
    public void shutdownMockS3(){
        s3Mock.stop();
    }
}

위에서 작성한 S3MockConfig를 @Import 어노테이션으로 임포트 해주었다.

이 후 잘 작동하는 것을 잘 테스트하고, @After 어노테이션으로 만든 메소드에서 s3Mock을 멈추었다. (s3Mock.shutdown())으로 작성하여도 된다.

아직 모르는게 많아 게시글에 잘못된 정보가 있을 수 있습니다. 혹시 잘못된 정보가 있다면, 댓글 혹은 메일로 알려주시면 최대한 빨리 수정하겠습니다!