mockito 在构造函数中注入时,@限定符在单元测试中不起作用

h6my8fg2  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(216)

我有一个应用程序,其单元测试工作正常。我正在尝试移动应用程序使用依赖注入,而不是使用@AutoWired注解。
在我进行更改之后,一些单元测试随机失败(没有对测试进行任何更改,只是更改了应用程序的依赖注入部分)。我假设在注入依赖时系统无法正确创建AmazonS3客户端。
请参见下面的屏幕截图,我正在尝试创建一个s3ClientAlphaBeta示例,但应用程序正在创建一个s3ClientGammaProd示例。

我还能错过什么呢?
缩写代码:

S3附件. java:

@Component
    public class S3Accessor {
        private AmazonS3 s3ClientAlphaBeta;
        private AmazonS3 s3ClientGammaProd;
        @Inject
        public S3Accessor(@Qualifier("s3ClientAlphaBeta") AmazonS3 s3ClientAlphaBeta,
                @Qualifier("s3ClientGammaProd") AmazonS3 s3ClientGammaProd) {
            this.s3ClientAlphaBeta = s3ClientAlphaBeta;
            this.s3ClientGammaProd = s3ClientGammaProd;
        }
public String getHtmlContent(final String deviceType, final String s3Key, final String region) {
        final String filePath = generateFilePath(deviceType.toLowerCase(Locale.ROOT), s3Key);
        AmazonS3 amazonS3 = s3ClientAlphaBeta;
        final String regionSpecificLegoBucket = S3BUCKET_NAME_BETA;
        final AmazonS3 regionSpecificAmazonS3 = amazonS3;
        return this.getHtmlContentFromS3(regionSpecificLegoBucket, filePath, regionSpecificAmazonS3);
    }

    private String getHtmlContentFromS3(final String bucketName, final String filePath, final AmazonS3 amazonS3) {
        String s3HtmlContent = amazonS3.getObjectAsString(bucketName, filePath);
        return s3HtmlContent;
    }

S3附件测试. java:

public class S3AccessorTest {
@InjectMocks
private S3Accessor s3Accessor;
@Spy
@Qualifier("s3ClientAlphaBeta")
private AmazonS3 s3ClientAlphaBeta;
@Spy
@Qualifier("s3ClientGammaProd")
private AmazonS3 s3ClientGammaProd;
private static final String TEST_VALID_STRING_DESKTOP = "<html><body>Some Content For DESKTOP</body></html>";
private static final String TEST_VALID_WRAPPED_STRING_DESKTOP =
        PAINTERS_LEGO_OPENING_DIV + TEST_VALID_STRING_DESKTOP + PAINTERS_LEGO_CLOSING_DIV;
private static final String TEST_VALID_S3_KEY = "/test/.1/main";
private static final String SLASH = "/";
static {
    AppConfig.destroy();
    AppConfig.initialize("TestApp",
            "TestGroup",
            new String[] { "--root=configuration/", "--domain=test", "--realm=Ramu" });
}
@BeforeEach
public void setup() {
    MockitoAnnotations.openMocks(this);
    s3Accessor.setup();
}
@Test
public void getHtmlContentForDesktop() {
    // Arrange
    when(s3ClientAlphaBeta.getObjectAsString(anyString(), eq(TEST_VALID_S3_KEY + SLASH + DESKTOP_VIEW)))
            .thenReturn(TEST_VALID_STRING_DESKTOP);
    // Act
    final String outputString = s3Accessor.getHtmlContent(DESKTOP, TEST_VALID_S3_KEY, US_ALPHA_BETA_REGION);
    // Assert
    assertEquals(TEST_VALID_WRAPPED_STRING_DESKTOP, outputString);
}

自定义根配置.java:

@Configuration
@ComponentScan("com.service.controller")
@Import({SmokeTestBeanConfiguration.class })
public class CustomRootConfig {
    private static final String NA_S3_SESSION_NAME = "S3Content";
    private static final int S3_SESSION_REFRESH_TIME = 3600;
    private static final String S3BUCKET_ARN_BETA = "arn:aws:iam::471963992020:role/ProdAccessForAccount";
    private static final String S3BUCKET_ARN_PROD = "arn:aws:iam::568948772290:role/ProdAccessForAccount";

    @Bean(name = "s3ClientAlphaBeta")
    @Singleton
    public AmazonS3 s3ClientAlphaBeta() {
        return AmazonS3ClientBuilder.standard()
                .withRegion(Regions.valueOf(US_ALPHA_BETA_REGION))
                .withCredentials(new STSAssumeRoleSessionCredentialsProvider
                        .Builder(S3BUCKET_ARN_BETA, NA_S3_SESSION_NAME)
                        .withRoleSessionDurationSeconds(S3_SESSION_REFRESH_TIME).build())
                .build();
    }

    @Bean(name = "s3ClientGammaProd")
    @Singleton
    public AmazonS3 s3ClientGammaProd() {
        return AmazonS3ClientBuilder.standard()
                .withRegion(Regions.valueOf(US_GAMMA_PROD_REGION))
                .withCredentials(new STSAssumeRoleSessionCredentialsProvider
                        .Builder(S3BUCKET_ARN_PROD, NA_S3_SESSION_NAME)
                        .withRoleSessionDurationSeconds(S3_SESSION_REFRESH_TIME).build())
                .build();
    }
deikduxw

deikduxw1#

我认为Mockito实际上并不能识别Spring中的@Qualifier注解,它以前工作的原因是Mockito进行了属性注入,因为没有其他方法可以做到这一点。
修改之后,在构造函数就位的情况下,Mockito从属性注入切换到构造函数注入。(AmazonS3).显然,使用构造函数注入时,Mockito不能很好地按名称区分参数,可能的原因是参数的名称在编译后没有保留,因此Mockito无法匹配它们,而是使用它找到的第一个具有匹配类型(s3ClientAlphaBetas3ClientGammaProd)的mock(spy),并将其用于两个参数以构造S3Accessor的示例。
为了避免您的问题并获得更多对如何创建被测试对象的控制,我建议放弃使用@InjectMocks并直接在被测试类中使用构造函数,即:

s3Accessor = new S3Accessor(s3ClientAlphaBeta, s3ClientGammaProd);

低于MockitoAnnotations.openMocks(this)的某个值。
您可以找到有关@InjectMocks注解如何工作here的更多信息。

相关问题