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

如何用Moq框架Mock C#.NET中SOAP Web方法的请求与响应?

如何用Moq Mock SOAP Web方法中的远程调用逻辑

我是C# Mock测试新手,现在需要测试SOAP Web方法CustomerCareResult的完整请求响应流程,但不想实际调用远程服务器。这个方法内部会调用两个包含远程调用的私有方法ApiCreateRequestObj和ApiCreateResponseObj,计划用Moq框架实现Mock。

现有代码如下:

public class TransactionService : System.Web.Services.WebService, 
TransactionServiceNS.ITransactionServiceSoap
{
    [WebMethod()]
    public CustomerPutResponse CustomerCareResult(CustomerRequest request)
    {
         var apiRequestObj = ApiCreateRequestObj(request);
         var apiResponseObj = ApiCreateResponseObj(apiRequestObj );
         return apiResponseObj;
    }

    private CustomerPutRequest ApiCreateRequestObj(CustomerRequest req)
    {
        // 实际会调用远程服务器,此处为伪代码
        return new CustomerPutRequest{
            Name = req.Name, 
            Address = req.Address,
            City = req.City, 
            State = req.State
        };
    }

    private CustomerPutResponse ApiCreateResponseObj(CustomerPutRequest cpReq)
    {
        // 实际会调用远程服务器,此处为伪代码
        return new CustomerPutResponse{/* 响应数据字段 */};
    }
}

核心思路

Moq无法直接Mock私有方法,所以首先需要重构代码,把远程调用的逻辑抽象为公共接口,让TransactionService依赖这个接口而非硬编码私有方法,这样就能用Moq模拟接口的实现,避免实际远程调用。

步骤1:提取远程调用逻辑到接口

创建一个接口,定义原来两个私有方法的功能:

public interface ICustomerApiClient
{
    CustomerPutRequest CreateRequestObject(CustomerRequest req);
    CustomerPutResponse CreateResponseObject(CustomerPutRequest cpReq);
}

实现这个接口的生产环境版本:

public class CustomerApiClient : ICustomerApiClient
{
    public CustomerPutRequest CreateRequestObject(CustomerRequest req)
    {
        // 保留原远程调用逻辑
        return new CustomerPutRequest{
            Name = req.Name, 
            Address = req.Address,
            City = req.City, 
            State = req.State
        };
    }

    public CustomerPutResponse CreateResponseObject(CustomerPutRequest cpReq)
    {
        // 保留原远程调用逻辑
        return new CustomerPutResponse{/* 响应数据字段 */};
    }
}

步骤2:修改TransactionService类,依赖注入接口

替换原有私有方法调用,通过构造函数注入ICustomerApiClient,同时保留无参构造函数兼容ASMX服务的默认实例化:

public class TransactionService : System.Web.Services.WebService, 
TransactionServiceNS.ITransactionServiceSoap
{
    private readonly ICustomerApiClient _apiClient;

    // 用于测试的构造函数,注入Mock对象
    public TransactionService(ICustomerApiClient apiClient)
    {
        _apiClient = apiClient;
    }

    // 兼容生产环境的无参构造函数
    public TransactionService() : this(new CustomerApiClient())
    {
    }

    [WebMethod()]
    public CustomerPutResponse CustomerCareResult(CustomerRequest request)
    {
         var apiRequestObj = _apiClient.CreateRequestObject(request);
         var apiResponseObj = _apiClient.CreateResponseObject(apiRequestObj);
         return apiResponseObj;
    }
}

步骤3:编写Moq测试用例

用Moq模拟ICustomerApiClient的行为,测试CustomerCareResult的逻辑(以xunit测试框架为例):

using Moq;
using Xunit;

public class TransactionServiceTests
{
    [Fact]
    public void CustomerCareResult_ShouldReturnExpectedResponse()
    {
        // 准备测试数据
        var testRequest = new CustomerRequest{
            Name = "Test User",
            Address = "123 St",
            City = "NY",
            State = "NY",
            AccountNumber = "12345"
        };

        var mockRequestObj = new CustomerPutRequest{
            Name = testRequest.Name,
            Address = testRequest.Address,
            City = testRequest.City,
            State = testRequest.State
        };

        var expectedResponse = new CustomerPutResponse{
            IsSuccess = true,
            Message = "处理成功"
        };

        // 创建Moq对象并设置预期行为
        var mockApiClient = new Mock<ICustomerApiClient>();
        mockApiClient.Setup(client => client.CreateRequestObject(testRequest))
                     .Returns(mockRequestObj);
        mockApiClient.Setup(client => client.CreateResponseObject(mockRequestObj))
                     .Returns(expectedResponse);

        // 实例化测试服务
        var service = new TransactionService(mockApiClient.Object);

        // 调用目标方法
        var actualResponse = service.CustomerCareResult(testRequest);

        // 断言结果符合预期
        Assert.Equal(expectedResponse.IsSuccess, actualResponse.IsSuccess);
        Assert.Equal(expectedResponse.Message, actualResponse.Message);

        // 验证接口方法是否被正确调用
        mockApiClient.Verify(client => client.CreateRequestObject(testRequest), Times.Once);
        mockApiClient.Verify(client => client.CreateResponseObject(mockRequestObj), Times.Once);
    }
}

关键说明

  • 重构必要性:Moq仅支持Mock公共接口或虚方法,私有方法无法直接Mock,抽象接口是最合理的解耦方式。
  • 兼容ASMX:保留无参构造函数,确保生产环境中Web服务能正常初始化,同时通过构造函数注入支持测试场景。
  • 场景扩展:通过修改Moq的Setup配置,可以测试CustomerCareResult在各种异常场景下的表现,比如远程调用返回错误、参数非法等。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 16:58:24