So basically I have a S3StorageService class that needs a S3Client:
@RequiredArgsConstructor
@Service
public class S3StorageService implements StorageService<S3FileUploadResult> {
private final S3Client client;
// ...
}
and I have a SongServiceImpl class:
@RequiredArgsConstructor
@Service
public class SongServiceImpl implements SongService {
private final StorageService<?> storageService;
@Transactional
@Override
public Song uploadSong(UploadSongDTO dto) {
// ...
storageService.upload(dto.file());
}
}
and I have a SongController class:
@RequiredArgsConstructor
@RequestMapping("/song")
@RestController
public class SongController {
private final SongService songService;
@PostMapping("/upload")
public ResponseEntity<Song> upload(@Valid UploadSongDTO dto) {
return ResponseEntity.ok(songService.uploadSong(dto));
}
}
so i want to write integration tests for this SongController#upload, so i need to somehow inject a mocked S3Client into spring context so S3StorageService can use this mocked s3 instead of a real one, here is what i tried:
static S3MockContainer s3Mock = new S3MockContainer("latest");
@BeforeEach
void setUp() {
final String endpoint = s3Mock.getHttpsEndpoint();
final S3Configuration serviceConfig = S3Configuration.builder()
.pathStyleAccessEnabled(true)
.build();
final SdkHttpClient httpClient = UrlConnectionHttpClient.builder()
.buildWithDefaults(AttributeMap.builder()
.put(TRUST_ALL_CERTIFICATES, Boolean.TRUE)
.build());
final S3Client s3Client = S3Client.builder() // somehow inject this into S3StorageService
.region(Region.of("auto"))
.endpointOverride(URI.create(endpoint))
.serviceConfiguration(serviceConfig)
.httpClient(httpClient)
.build();
applicationContext.registerBean(S3Client.class, () -> s3Client); // does not work. `Parameter 0 of constructor in me.approximations.music.services.storage.impl.S3StorageService required a bean of type 'software.amazon.awssdk.services.s3.S3Client' that could not be found.`
}
Already described above.