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

单元测试中如何Mock Service的Response对象避免空引用异常?

解决方案

问题出在ServiceStack的Service基类的Response属性未被正确初始化。单元测试场景下,服务不会自动获取请求上下文的IResponse实例,需要手动Mock并关联到服务实例。

步骤1:Mock IResponse 实例

在测试的Arrange阶段,创建IResponse的Mock对象:

var responseMock = new Mock<IResponse>();

步骤2:将Mock关联到服务

有两种可靠的方式实现关联:

方式一:直接赋值给服务的Response属性

解析出服务实例后,直接设置Response属性:

var service = BaseAppHost.Container.Resolve<EventServices>();
// 新增:设置Mock的Response
service.Response = responseMock.Object;

方式二:通过RequestContext关联

如果服务依赖RequestContext获取Response,给RequestContext的Mock设置Response返回值,并确保服务的RequestContext被正确赋值:

// 在创建requestContextMock后添加
requestContextMock.Setup(x => x.Response).Returns(responseMock.Object);

// 解析服务后设置RequestContext(如果容器未自动注入)
var service = BaseAppHost.Container.Resolve<EventServices>();
service.RequestContext = requestContextMock.Object;

修改后的完整测试代码示例

[Test, Order(1)]
public void NewEventTest_Successful()
{
    // Arrange
    var request = new NewEvent
    {
        // 填充请求数据
    };
    
    var eventData = new EventData().PopulateWithNonDefaultValues(request);
    var eventId = new Random().NextInt64();
    
    var eventManagerMock = new Mock<IEventManager>();
    var requestContextMock = new Mock<RequestContext>();
    var requestMock = new Mock<IRequest>();
    // 新增:Mock IResponse
    var responseMock = new Mock<IResponse>();

    eventManagerMock.Setup(x => x.CreateNewEvent(
        It.Is<EventData>(y => 
            y.Id.Equals(eventData.Id) &&
            // 其他断言条件
            y.Metadata.Zip(eventData.Metadata, (metaY, metaR) => 
                metaY.Key == metaR.Key &&
                metaY.Value == metaR.Value).All(result => result)
            )
    )).Returns(eventId)
    .Verifiable("IEventManager.CreateNewEvent was not invoked.");
    
    // 方式二可选:给RequestContext设置Response
    requestContextMock.Setup(x => x.Response).Returns(responseMock.Object);
    
    BaseAppHost.Container.Register(eventManagerMock.Object);
    BaseAppHost.Container.Register(requestContextMock.Object);
    BaseAppHost.Container.Register(requestMock.Object);
    // 可选:注册IResponse到容器
    BaseAppHost.Container.Register(responseMock.Object);
    
    var service = BaseAppHost.Container.Resolve<EventServices>();
    // 方式一:直接设置服务的Response
    service.Response = responseMock.Object;
    // 方式二:设置服务的RequestContext
    // service.RequestContext = requestContextMock.Object;

    // Act
    var response = service.Post(request);

    // Assert
    eventManagerMock.Verify();
    // 可选:验证Response.StatusCode是否被设置为Created
    responseMock.VerifySet(x => x.StatusCode = (int)HttpStatusCode.Created, Times.Once);
}

额外说明

如果你的服务是通过构造函数注入IResponse而非依赖基类属性,只需将responseMock.Object注册到容器即可,无需手动赋值。

内容的提问来源于stack exchange,提问作者Carlos Ramírez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 07:45:04