You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建Azure.AI.OpenAI.ChatCompletions模拟对象以测试OpenAI相关函数?

测试调用Azure OpenAI的函数:解决ChatCompletions模拟问题

方法一:通过反射创建ChatCompletions实例

由于ChatCompletions没有公开构造函数,我们可以利用反射实例化它,并构建所需的响应结构:

步骤1:构建基础响应对象

先创建模拟的ChatMessage和ChatChoice(这两个类有公开构造函数):

var mockMessage = new ChatMessage(ChatRole.Assistant, "这是模拟的LLM响应内容");
var mockChoice = new ChatChoice(0, mockMessage, CompletionsFinishReason.Stop);

步骤2:反射创建ChatCompletions实例

// 获取ChatCompletions的私有构造函数
var chatCompletionsType = typeof(ChatCompletions);
var constructor = chatCompletionsType.GetConstructor(
    BindingFlags.Instance | BindingFlags.NonPublic, 
    Type.EmptyTypes);

// 实例化ChatCompletions
var chatCompletions = (ChatCompletions)constructor.Invoke(null);

// 设置Choices属性(通过反射访问)
var choicesProperty = chatCompletionsType.GetProperty("Choices");
choicesProperty.SetValue(chatCompletions, new List<ChatChoice> { mockChoice }.AsReadOnly());

步骤3:创建Response并模拟客户端

使用Azure.Core的Response.FromValue方法构建响应对象,再用Moq模拟OpenAIClient:

// 创建模拟的原始Response(用Moq快速实现)
var mockRawResponse = new Mock<Response>().Object;
var mockResponse = Response.FromValue(chatCompletions, mockRawResponse);

// 模拟OpenAIClient的GetChatCompletionsAsync方法
var mockClient = new Mock<OpenAIClient>();
mockClient.Setup(c => c.GetChatCompletionsAsync(
    It.IsAny<string>(), 
    It.IsAny<ChatCompletionsOptions>(), 
    It.IsAny<CancellationToken>()))
.ReturnsAsync(mockResponse);

方法二:抽象客户端接口(更优的可测试性方案)

为了避免依赖具体实现类带来的测试麻烦,建议给OpenAIClient套一层接口:

步骤1:定义接口

public interface IOpenAIChatClient
{
    Task<Response<ChatCompletions>> GetChatCompletionsAsync(
        string deploymentName, 
        ChatCompletionsOptions conversation, 
        CancellationToken cancellationToken = default);
}

步骤2:实现接口包装类

public class OpenAIChatClient : IOpenAIChatClient
{
    private readonly OpenAIClient _client;

    public OpenAIChatClient(OpenAIClient client)
    {
        _client = client;
    }

    public async Task<Response<ChatCompletions>> GetChatCompletionsAsync(
        string deploymentName, 
        ChatCompletionsOptions conversation, 
        CancellationToken cancellationToken = default)
    {
        return await _client.GetChatCompletionsAsync(deploymentName, conversation, cancellationToken)
            .ConfigureAwait(false);
    }
}

步骤3:重构业务函数并测试

将原函数中的OpenAIClient替换为IOpenAIChatClient,测试时直接模拟接口:

// 模拟接口返回预期响应
var mockChatClient = new Mock<IOpenAIChatClient>();
mockChatClient.Setup(c => c.GetChatCompletionsAsync(
    It.IsAny<string>(), 
    It.IsAny<ChatCompletionsOptions>(), 
    It.IsAny<CancellationToken>()))
.ReturnsAsync(mockResponse); // mockResponse可通过方法一的方式创建

// 注入模拟对象到业务类并执行测试
var service = new YourService(mockChatClient.Object);
var result = await service.GetChatCompletion("test-deployment", new ChatCompletionsOptions());
Assert.Equal("这是模拟的LLM响应内容", result);

注意事项

  • 使用反射时需注意:Azure SDK的内部结构可能随版本变化,升级SDK后需验证反射代码是否仍有效。
  • 接口抽象方案更符合依赖倒置原则,能提升代码的可维护性和可测试性,推荐优先使用。

内容的提问来源于stack exchange,提问作者Mark Wiemer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:10:29