首页 > 解决方案 > 针对经过身份验证的远程系统进行 Spring 引导测试的最佳实践

问题描述

我编写了利用Azure SDK for Blob与 Blob 存储进行交互的代码。

作为一个聪明而尽职的开发人员,我没有通过导航实时应用程序来测试我的代码,而是创建了一个 Spring Boot JUnit 测试并花了几个小时来修复我所有的错误。事实上,我没有使用任何类型的嘲笑,因为我的问题是以正确的方式使用库。我针对 blob 存储的实时实例运行代码,并检查我的所有 Java 方法是否按预期工作。

我写在这里是因为

我从一开始就知道将凭据硬编码到代码中是最糟糕的做法,但从今天早上开始,我想专注于我的任务。现在我想采用最佳实践。我在问重新设计测试结构

测试代码是这样的。

该代码创建一个临时容器并尝试存储/检索/删除 blob。它使用 GUID 创建一个唯一的私有工作区,在测试完成后清除。

@SpringBootTest(classes = FileRepositoryServiceAzureBlobImplTest.class)
@SpringBootConfiguration
@TestConfiguration
@TestPropertySource(properties = {
        "azure-storage-container-name:amlcbackendjunit",
        "azure-storage-connection-string:[not going to post it on Stackoverflow before rotating it]"
})
class FileRepositoryServiceAzureBlobImplTest {

    private static final Resource LOREM_IPSUM = new ClassPathResource("loremipsum.txt", FileRepositoryServiceAzureBlobImplTest.class);
    private FileRepositoryServiceAzureBlobImpl uut;
    private BlobContainerClient blobContainerClient;
    private String loremChecksum;

    @Value("${azure-storage-connection-string}")
    private String azureConnectionString;
    @Value("${azure-storage-container-name}")
    private String azureContainerName;

    @BeforeEach
    void beforeEach() throws IOException {

        String containerName = azureContainerName + "-" + UUID.randomUUID();
        blobContainerClient = new BlobContainerClientBuilder()
                .httpLogOptions(new HttpLogOptions().setApplicationId("az-sp-sb-aml"))
                .clientOptions(new ClientOptions().setApplicationId("az-sp-sb-aml"))
                .connectionString(azureConnectionString)
                .containerName(containerName)
                .buildClient()
        ;


        blobContainerClient.create();
        uut = spy(new FileRepositoryServiceAzureBlobImpl(blobContainerClient));
        try (InputStream loremIpsumInputStream = LOREM_IPSUM.getInputStream();) {
            loremChecksum = DigestUtils.sha256Hex(loremIpsumInputStream);
        }

        blobContainerClient
                .getBlobClient("fox.txt")
                .upload(BinaryData.fromString("The quick brown fox jumps over the lazy dog"));

    }

    @AfterEach
    void afterEach() throws IOException {
        blobContainerClient
                .delete();
    }

    @Test
    void store_ok() {
        String desiredFileName = "loremIpsum.txt";


        FileItemDescriptor output = assertDoesNotThrow(() -> uut.store(LOREM_IPSUM, desiredFileName));
        assertAll(
                () -> assertThat(output, is(notNullValue())),
                () -> assertThat(output, hasProperty("uri", hasToString(Matchers.startsWith("azure-blob://")))),
                () -> assertThat(output, hasProperty("size", equalTo(LOREM_IPSUM.contentLength()))),
                () -> assertThat(output, hasProperty("checksum", equalTo(loremChecksum))),
                () -> {
                    String localPart = substringAfter(output.getUri().toString(), "azure-blob://");
                    assertAll(
                            () -> assertTrue(blobContainerClient.getBlobClient(localPart).exists())
                    );
                }
        );
    }

}

在生产中(也包括在 SIT/UAT 中),真正的 Spring Boot 应用程序将从 Container 环境中获取配置,包括存储连接字符串。是的,对于这种测试,我也可以避免使用 Spring 和@TestPropertySource,因为我没有利用上下文中的任何 bean。

问题

我想问我如何修改这个测试以便

  1. 将连接字符串与代码解耦
  2. 如果由于某种原因连接字符串不存在,则软忽略测试(例如,开发人员第一次下载项目并想要启动)(注 1)
  3. 从 Azure DevOps 管道集成此测试(使用有效的连接字符串),我可以在其中配置几乎任何环境变量等

这是由测试组成的构建工作

          - task: Gradle@2
            displayName: Build with Gradle
            inputs:
              gradleWrapperFile: gradlew
              gradleOptions: -Xmx3072m $(gradleJavaProperties)
              options: -Pci=true -PbuildId=$(Build.BuildId) -PreleaseType=${{parameters.releaseType}}
              jdkVersionOption: 1.11
              jdkArchitectureOption: x64
              publishJUnitResults: true
              sqAnalysisEnabled: true
              sqGradlePluginVersionChoice: specify
              sqGradlePluginVersion: 3.2.0
              testResultsFiles: '$(System.DefaultWorkingDirectory)/build/test-results/**/TEST-*.xml'
              tasks: clean build

注 1:无需存储连接字符串即可启动实时应用程序。它回退到本地临时目录。

标签: javaspring-bootazurejunitcredentials

解决方案


推荐阅读