You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala替换AmazonS3客户端后单元测试403权限问题的解决

问题解决:Mock AmazonS3 时出现403 Access Denied的处理方案

问题背景

将S3Repository类的uploadCsvToS3方法中已弃用的AmazonS3Client替换为AmazonS3,通过AmazonS3ClientBuilder构建客户端并调用putObject方法,业务功能运行正常,但单元测试阶段出现异常:

  • 测试中已MockAmazonS3客户端并通过Guice绑定
  • 设置Mockito预期返回PutObjectResult,但执行测试时抛出**Access Denied(403)**错误
  • 尝试配置密钥、PowerMockito等方案均无效

问题代码

业务实现代码

val creds = DefaultAWSCredentialsProviderChain.getInstance()
val awsRegion: Regions = Regions.fromName(configuration.get[String]("aws.s3.region"))
val client: AmazonS3 = AmazonS3ClientBuilder.standard().withRegion(awsRegion).withCredentials(creds).build()
val fileName = produceFileNameForVersion(params_to_this_method)
client.putObject(AWSS3Bucket, fileName, file.toFile)

单元测试代码

val client = mock[AmazonS3]
override def fakeApplication(): Application = new GuiceApplicationBuilder()
  .overrides(bind[AmazonS3].toInstance(client))

Mockito.when(client.putObject(MockitoMatchers.eq(s3Bucket), MockitoMatchers.anyString(), MockitoMatchers.eq(file))) thenReturn new PutObjectResult
val s3Repository : S3Repository = app.injector.instanceOf[S3Repository]
val s3Location = s3Repository.uploadCsvToS3(file.toPath).futureValue
assert(s3Location.fileName.nonEmpty)

解决方案

问题根源是业务代码直接在方法内实例化AmazonS3客户端,导致Guice绑定的Mock实例无法被注入,实际调用的是真实AWS客户端,从而触发403权限错误。

通过创建AmazonS3ClientProvider类封装客户端实例化逻辑,再通过Guice绑定该Provider,让业务代码通过依赖注入获取客户端,确保测试时Mock实例能被正确注入。

关键绑定配置

bind(classOf[AmazonS3]).toProvider(classOf[AmazonS3ClientProvider])

调整后的业务代码思路

将客户端实例化逻辑移到Provider中,业务类通过构造函数注入AmazonS3实例:

class S3Repository @Inject()(amazonS3: AmazonS3, configuration: Configuration) {
  def uploadCsvToS3(filePath: Path): Future[S3Location] = {
    val fileName = produceFileNameForVersion(params_to_this_method)
    amazonS3.putObject(AWSS3Bucket, fileName, filePath.toFile)
    // 后续业务逻辑...
  }
}

AmazonS3ClientProvider示例

class AmazonS3ClientProvider @Inject()(configuration: Configuration) extends Provider[AmazonS3] {
  override def get(): AmazonS3 = {
    val creds = DefaultAWSCredentialsProviderChain.getInstance()
    val awsRegion: Regions = Regions.fromName(configuration.get[String]("aws.s3.region"))
    AmazonS3ClientBuilder.standard().withRegion(awsRegion).withCredentials(creds).build()
  }
}

修改后,单元测试中Guice绑定的MockAmazonS3实例会被正确注入到S3Repository中,避免调用真实AWS服务,解决403错误。


内容的提问来源于stack exchange,提问作者Nili Al

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:25:16