使用Mockito测试Azure存储服务层报Invalid connection string错误如何解决
问题根因
你当前测试抛出异常的直接原因是@InjectMocks初始化AzureCloudStorageService时,依赖的PropertyResolver没有被Mock,导致读取到的connectionString为null,传入Azure客户端构造方法时触发非法连接串校验失败。
你原本设想的不做大量Mock直接调用方法验证是集成测试的逻辑,需要加载Spring上下文读取配置,而你当前编写的是单元测试,需要Mock所有外部依赖避免真实调用第三方服务。
解决方案
方案1:单元测试(无需连接真实Azure服务)
第一步:引入依赖(如果未引入)
要Mock构造方法需要引入mockito-inline依赖,Maven配置如下:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>和你项目中mockito-core版本一致</version> <scope>test</scope> </dependency>
第二步:编写单元测试代码
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockedConstruction; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.env.PropertyResolver; import org.springframework.web.multipart.MultipartFile; import com.azure.storage.blob.BlobClient; import com.azure.storage.blob.BlobContainerClient; import com.azure.storage.blob.BlobServiceClient; import com.azure.storage.blob.BlobServiceClientBuilder; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) public class AzureCloudStorageServiceTest { @Mock private PropertyResolver propertyResolver; @Mock private ModelMapper modelMapper; @Mock private BlobServiceClient blobServiceClient; @Mock private BlobContainerClient blobContainerClient; @Mock private BlobClient blobClient; @InjectMocks private AzureCloudStorageService azureCloudStorageService; @BeforeEach void setUp() { // Stub配置读取的返回值,替换null为合法的伪造配置 when(propertyResolver.getProperty("azure.connection.string")).thenReturn("fake-connection-string"); when(propertyResolver.getProperty("azure.container.name")).thenReturn("test-container"); } @Test void upload_shouldReturnValidBlobUrlWhenSuccess() throws Exception { // 准备测试数据 MultipartFile testFile = ModelUtils.getFile(); String expectedBlobUrl = "https://test.blob.core.windows.net/test-container/test.jpg"; String originalFileName = testFile.getOriginalFilename(); // Mock BlobServiceClientBuilder构造及调用逻辑 try (MockedConstruction<BlobServiceClientBuilder> mockedBuilder = mockConstruction(BlobServiceClientBuilder.class)) { // Stub构造器链式调用逻辑 BlobServiceClientBuilder builderMock = mockedBuilder.constructed().get(0); when(builderMock.connectionString(anyString())).thenReturn(builderMock); when(builderMock.buildClient()).thenReturn(blobServiceClient); // Stub后续Azure客户端调用逻辑 when(blobServiceClient.getBlobContainerClient("test-container")).thenReturn(blobContainerClient); when(blobContainerClient.getBlobClient(argThat(blobName -> blobName.endsWith(originalFileName)))).thenReturn(blobClient); doNothing().when(blobClient).upload(any(), eq(testFile.getSize())); when(blobClient.getBlobUrl()).thenReturn(expectedBlobUrl); // 执行测试方法 String actualBlobUrl = azureCloudStorageService.upload(testFile); // 验证结果及调用链路 assertEquals(expectedBlobUrl, actualBlobUrl); verify(blobClient, times(1)).upload(any(InputStream.class), eq(testFile.getSize())); } } }
方案2:集成测试(真实调用Azure服务验证)
如果你需要验证真实的上传逻辑,就采用集成测试方案:
- 在
test/resources/application.properties中添加真实的Azure测试账号配置:
azure.connection.string=你的Azure存储账号真实连接串 azure.container.name=你的测试容器名称
- 编写集成测试代码:
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.web.multipart.MultipartFile; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest public class AzureCloudStorageServiceIntegrationTest { @Autowired private AzureCloudStorageService azureCloudStorageService; @Test void upload_shouldReturnValidBlobUrlWhenSuccess() { MultipartFile testFile = ModelUtils.getFile(); String blobUrl = azureCloudStorageService.upload(testFile); // 验证返回的url不为空、包含容器名等规则即可,不需要固定值匹配 assertNotNull(blobUrl); assertTrue(blobUrl.contains("test-container")); } }
注意事项
你原测试中写的expected = "image"不符合实际逻辑,服务返回的是完整的Azure Blob访问URL,不要做固定值匹配,要么Mock返回固定URL做单元测试断言,要么集成测试时做规则校验。
内容的提问来源于stack exchange,提问作者Євген Буфан
相关产品推荐
相关产品推荐

