[英]Best practices for Spring boot testing against authenticated remote system
I have written code that leverages Azure SDK for Blobs in order to interact with the blob storage.我编写了利用Azure SDK 的代码,以便与 Blob 存储交互。
As a clever and dutiful developer, I have not tested my code by navigating the live application, but rather created a Spring Boot JUnit test and spent a few hours fixing all my mistakes.作为一名聪明而尽职的开发人员,我没有通过导航实时应用程序来测试我的代码,而是创建了一个 Spring Boot JUnit 测试并花了几个小时来修复我所有的错误。 I didn't use anyh kind of mocking, in fact, as my problem was using the library the correct way.事实上,我没有使用任何类型的 mocking,因为我的问题是以正确的方式使用库。 I ran the code against a live instance of a blob storage and checked that all my Java methods worked as expected.我针对 blob 存储的实时实例运行代码,并检查我的所有 Java 方法是否按预期工作。
I am writing here because我写在这里是因为
I know from the very beginning that hardcoding credentials into code is a worst practice, but since this morning I wanted to focus on my task.我从一开始就知道将凭据硬编码到代码中是最糟糕的做法,但从今天早上开始我想专注于我的任务。 Now I want to adopt the best practices.现在我想采用最佳实践。 I am asking about redesigning the test structure我问的是重新设计测试结构
Testing code is this.测试代码是这样的。
The code creates an ephemeral container and tries to store/retrieve/delete blobs.该代码创建一个临时容器并尝试存储/检索/删除 blob。 It uses a GUID to create a unique private workspace, to clear after test is finished.它使用 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())
);
}
);
}
}
In production (but also in SIT/UAT), the real Spring Boot application will get the configuration from the Container environment, including the storage connection string.在生产中(也包括在 SIT/UAT 中),真正的 Spring Boot 应用程序将从 Container 环境中获取配置,包括存储连接字符串。 Yes, for this kind of test I could also avoid using Spring and @TestPropertySource
, because I'm not leveraging any bean from the context.是的,对于这种测试,我也可以避免使用 Spring 和@TestPropertySource
,因为我没有利用上下文中的任何 bean。
I want to ask how can I amend this test in order to我想问一下如何修改这个测试以便
Here is the build job comprised of tests这是由测试组成的构建作业
- 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
Note 1: the live application can be kick-started without the storage connection string.注 1:实时应用程序可以在没有存储连接字符串的情况下启动。 It falls back to a local temporary directory.它回退到本地临时目录。
The answer is a bit complex to explain, so I did my best答案解释起来有点复杂,所以我尽力了
Note that the original variable names are redacted and YMMV if you try to recreate the example with the exact keys I used请注意,如果您尝试使用我使用的确切键重新创建示例,则原始变量名称和 YMMV 已被编辑
Example name testStorageAccountConnectionString
示例名称testStorageAccountConnectionString
- 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)
${azure.storageConnectionString}
from an environment variable AZURE_STORAGE_CONNECTION_STRING
. Spring Boot 从环境变量AZURE_STORAGE_CONNECTION_STRING
接受占位符${azure.storageConnectionString}
。 Please read the docs and try it locally first.请阅读文档并先在本地尝试。 This means we need to run the test with an environment variable propely set in order to resolve the placeholder这意味着我们需要使用适当设置的环境变量来运行测试,以解析占位符-D
to add an environment variable. Gradle可以用-D
运行加个环境变量。 -DAZURE_STORAGE_CONNECTION_STRING=$(AZURE_STORAGE_CONNECTION_STRING)
adds an environment variable AZURE_STORAGE_CONNECTION_STRING
to the test run equal to the pipeline environment variable AZURE_STORAGE_CONNECTION_STRING
(not that fantasy) -DAZURE_STORAGE_CONNECTION_STRING=$(AZURE_STORAGE_CONNECTION_STRING)
将环境变量AZURE_STORAGE_CONNECTION_STRING
添加到测试运行中,等于管道环境变量AZURE_STORAGE_CONNECTION_STRING
(不是那个幻想)Gradle's env attributes set environment variable for the pipeline container. Gradle 的env属性为管道容器设置环境变量。 In this case, we make sure that Gradle runs with AZURE_STORAGE_CONNECTION_STRING
set to testStorageAccountConnectionString
.在这种情况下,我们确保 Gradle 在AZURE_STORAGE_CONNECTION_STRING
设置为testStorageAccountConnectionString
的情况下运行。 Env is the only place where Azure pipelines agent will resolve and set free the content of the secret variable Env 是 Azure 管道代理解析和释放秘密变量内容的唯一地方
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.