如何Mock Azure CryptographyClient的EncryptAsync并返回有效EncryptResult?
解决Azure CryptographyClient.EncryptAsync的Mock问题及替代测试方案
一、修改Mock生成合法EncryptResult的方法
由于EncryptResult是不可变类(无公共setter),可以通过反射修改私有字段生成有效实例,具体步骤如下:
- 使用
Activator.CreateInstance创建EncryptResult实例(绕过无公共构造的限制) - 通过反射定位
EncryptResult的私有字段(通常名为_ciphertext)并赋值 - 将该实例作为Mock方法的返回值
示例代码(结合Moq框架):
using System.Reflection; using Azure.Security.KeyVault.Keys.Cryptography; using Moq; // 创建EncryptResult实例 var encryptResult = Activator.CreateInstance<EncryptResult>(); // 反射获取私有字段并设置模拟密文 var ciphertextField = typeof(EncryptResult).GetField( "_ciphertext", BindingFlags.Instance | BindingFlags.NonPublic); ciphertextField.SetValue(encryptResult, Convert.FromBase64String("aGVsbG8gd29ybGQ=")); // 模拟密文 // Mock CryptographyClient的EncryptAsync方法 var mockCryptoClient = new Mock<CryptographyClient>(); mockCryptoClient.Setup(c => c.EncryptAsync( It.IsAny<EncryptionAlgorithm>(), It.IsAny<byte[]>(), default)) .ReturnsAsync(encryptResult);
注意:私有字段名称可能随Azure SDK版本变化,若出现找不到字段的情况,可通过调试查看EncryptResult的内部字段名调整。
二、其他测试方案
1. 引入抽象层解耦依赖
对CryptographyClient的加密能力进行抽象,定义自定义接口,让KeyVaultClientWrapper依赖该接口而非直接依赖Azure SDK类,测试时可自由Mock返回值。
示例代码:
// 自定义加密服务接口 public interface IKeyVaultCryptoService { Task<IEncryptResult> EncryptAsync( EncryptionAlgorithm algorithm, byte[] plaintext, CancellationToken cancellationToken = default); } // 自定义加密结果接口 public interface IEncryptResult { byte[] Ciphertext { get; } } // 实现类包装Azure SDK的CryptographyClient public class KeyVaultCryptoService : IKeyVaultCryptoService { private readonly CryptographyClient _client; public KeyVaultCryptoService(CryptographyClient client) { _client = client; } public async Task<IEncryptResult> EncryptAsync( EncryptionAlgorithm algorithm, byte[] plaintext, CancellationToken cancellationToken = default) { var sdkResult = await _client.EncryptAsync(algorithm, plaintext, cancellationToken); return new EncryptResultAdapter(sdkResult); } // 适配器类,将SDK的EncryptResult转换为自定义接口 private class EncryptResultAdapter : IEncryptResult { private readonly EncryptResult _innerResult; public EncryptResultAdapter(EncryptResult innerResult) { _innerResult = innerResult; } public byte[] Ciphertext => _innerResult.Ciphertext; } }
测试时直接Mock自定义接口,无需处理Azure SDK的限制:
var mockCryptoService = new Mock<IKeyVaultCryptoService>(); // 自定义测试用的加密结果 var testResult = new Mock<IEncryptResult>(); testResult.Setup(r => r.Ciphertext).Returns(Convert.FromBase64String("测试密文")); mockCryptoService.Setup(s => s.EncryptAsync( It.IsAny<EncryptionAlgorithm>(), It.IsAny<byte[]>(), default)) .ReturnsAsync(testResult.Object); // 将Mock实例注入KeyVaultClientWrapper进行测试 var wrapper = new KeyVaultClientWrapper(mockCryptoService.Object);
2. 使用Azurite进行集成测试
如果单元测试的Mock方案过于繁琐,可采用集成测试,使用Azurite(Azure本地模拟器)模拟Key Vault服务,直接调用真实的加密流程,测试结果更贴近生产环境,无需Mock SDK类。
只需在测试前启动Azurite,创建测试用的密钥,然后让CryptographyClient连接到Azurite的端点即可完成测试。
内容的提问来源于stack exchange,提问作者mohanraj
相关产品推荐
相关产品推荐

