繁体   English   中英

针对经过身份验证的远程系统进行 Spring 启动测试的最佳实践

[英]Best practices for Spring boot testing against authenticated remote system

我编写了利用Azure SDK 的代码,以便与 Blob 存储交互。

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

我写在这里是因为

  • 最后,我在我的源文件中硬编码了凭据。 仓库是公司私有的仓库,没有那个害处。 凭证可以轮换,开发者都可以从Azure门户访问并获取凭证。 但我仍然不喜欢将凭据推送到代码中的想法
  • 让这些 junit 测试在 Azure DevOps 管道上运行可能是个好主意

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

测试代码是这样的。

该代码创建一个临时容器并尝试存储/检索/删除 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:实时应用程序可以在没有存储连接字符串的情况下启动。 它回退到本地临时目录。

答案解释起来有点复杂,所以我尽力了

长话短说

请注意,如果您尝试使用我使用的确切键重新创建示例,则原始变量名称和 YMMV 已被编辑

  • 创建一个包含连接字符串的秘密管道变量,并将其埋入*到管道中

示例名称testStorageAccountConnectionString

管道变量

  • 更改Gradle任务
              - task: Gradle@3
                displayName: Build with Gradle
                inputs:
                  gradleWrapperFile: gradlew
                  gradleOptions: -Xmx10240m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -DAZURE_STORAGE_CONNECTION_STRING=$(AZURE_STORAGE_CONNECTION_STRING)
                  options: --build-cache -Pci=true -PgitCommitId=$(Build.SourceVersion) -PbuildId=$(Build.BuildId) -Preckon.stage=${{parameters.versionStage}} -Preckon.scope=${{parameters.versionScope}}
                  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
                env:
                 AZURE_STORAGE_CONNECTION_STRING: $(testStorageAccountConnectionString)

解释

  • Spring Boot 从环境变量AZURE_STORAGE_CONNECTION_STRING接受占位符${azure.storageConnectionString} 请阅读文档并先在本地尝试。 这意味着我们需要使用适当设置的环境变量来运行测试,以解析占位符
  • Gradle可以用-D运行加个环境变量。 -DAZURE_STORAGE_CONNECTION_STRING=$(AZURE_STORAGE_CONNECTION_STRING)将环境变量AZURE_STORAGE_CONNECTION_STRING添加到测试运行中,等于管道环境变量AZURE_STORAGE_CONNECTION_STRING (不是那个幻想)
  • Azure DevOps 管道保护秘密变量免遭不必要的访问。 我们将管道变量创建为秘密变量,因此还有一个技巧需要先做

Gradle 的env属性为管道容器设置环境变量。 在这种情况下,我们确保 Gradle 在AZURE_STORAGE_CONNECTION_STRING设置为testStorageAccountConnectionString的情况下运行。 Env 是 Azure 管道代理解析和释放秘密变量内容的唯一地方

  • 无法再从 web 接口检索机密。 Azure 管道就是为此而设计的

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM