java - 针对经过身份验证的远程系统进行 Spring 引导测试的最佳实践
问题描述
我编写了利用Azure SDK for Blob与 Blob 存储进行交互的代码。
作为一个聪明而尽职的开发人员,我没有通过导航实时应用程序来测试我的代码,而是创建了一个 Spring Boot JUnit 测试并花了几个小时来修复我所有的错误。事实上,我没有使用任何类型的嘲笑,因为我的问题是以正确的方式使用库。我针对 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)
- 从 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:无需存储连接字符串即可启动实时应用程序。它回退到本地临时目录。
解决方案
推荐阅读
- python - dask 进程调度程序运行不佳
- reactjs - 如何在 nx 框架中开玩笑地忽略测试文件的执行
- docker - 如何构建和部署 pgadmin 到 OpenShift?
- vb.net - VB.net - 从共享文件夹中读取 .msg 文件并提取其中的附件
- javascript - 无法使用 v-for 获取动态添加的组件的 ID
- javascript - 获取 Angular 指令表标题行中的列索引
- keycloak - 从 keycloak jwt 令牌获取 ID(不是 clientId)
- typescript - 从规则中获取 »className«
- plsql - 使用 PLSQL 发送带有附件的消息
- json - 用于 json 文档的简单数据 porfiler