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

如何测试返回IHttpActionResult的Web API v2所有HTTP状态码

测试返回<IHttpActionResult>的Web API状态码指南

针对你遇到的测试Web API v2中<IHttpActionResult>类型返回值的问题,尤其是Post接口的Created状态码测试,我结合你的代码给出完整的测试方案。核心思路是将返回的actionResult转换为对应的具体实现类,然后验证状态码、类型和业务内容是否符合预期。


1. 先补全你未完成的GetById测试

你的GetById的NotFound测试代码未完成,这里补全并补充异常测试:

[TestMethod]
public void GetByIdReturnsNotFound()
{
    // Arrange
    mockRepository.Setup(x => x.GetById(It.IsAny<int>())).Returns((Student)null);
    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Get(999); // 传入不存在的ID
    var notFoundResult = actionResult as NotFoundResult;

    // Assert
    Assert.IsNotNull(notFoundResult);
    Assert.AreEqual(HttpStatusCode.NotFound, notFoundResult.StatusCode);
}

[TestMethod]
public void GetByIdReturnsException()
{
    // Arrange
    mockRepository.Setup(x => x.GetById(It.IsAny<int>())).Throws<Exception>();
    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Get(1);
    var exceptionResult = actionResult as ExceptionResult;

    // Assert
    Assert.IsNotNull(exceptionResult);
    Assert.AreEqual(HttpStatusCode.InternalServerError, exceptionResult.StatusCode);
    Assert.IsInstanceOfType(exceptionResult.Exception, typeof(Exception));
}

2. 重点:测试Post接口的Created状态码

你的Post接口在保存成功时返回Content(HttpStatusCode.Created, student),对应NegotiatedContentResult<T>类型,测试时可以直接转换后验证:

// Post接口测试集
[TestMethod]
public void PostReturnsCreatedStatus()
{
    // Arrange
    var fakeStudentModel = new StudentModel { Name = "Test Student" };
    var fakeStudent = new Student { Id = 1, Name = "Test Student" };
    
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Returns(fakeStudent);
    mockRepository.Setup(x => x.Save(fakeStudent)).Returns(1); // 返回大于0代表保存成功

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Post(fakeStudentModel);
    var contentResult = actionResult as NegotiatedContentResult<Student>;

    // Assert
    Assert.IsNotNull(contentResult);
    Assert.AreEqual(HttpStatusCode.Created, contentResult.StatusCode);
    Assert.AreEqual(fakeStudent.Id, contentResult.Content.Id);
    Assert.AreEqual(fakeStudent.Name, contentResult.Content.Name);
}

[TestMethod]
public void PostReturnsInternalServerErrorWhenSaveFails()
{
    // Arrange
    var fakeStudentModel = new StudentModel();
    var fakeStudent = new Student();
    
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Returns(fakeStudent);
    mockRepository.Setup(x => x.Save(fakeStudent)).Returns(0); // 返回0代表保存失败

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Post(fakeStudentModel);
    var statusCodeResult = actionResult as StatusCodeResult;

    // Assert
    Assert.IsNotNull(statusCodeResult);
    Assert.AreEqual(HttpStatusCode.InternalServerError, statusCodeResult.StatusCode);
}

[TestMethod]
public void PostReturnsExceptionResultWhenErrorOccurs()
{
    // Arrange
    var fakeStudentModel = new StudentModel();
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Throws<Exception>();

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Post(fakeStudentModel);
    var exceptionResult = actionResult as ExceptionResult;

    // Assert
    Assert.IsNotNull(exceptionResult);
    Assert.AreEqual(HttpStatusCode.InternalServerError, exceptionResult.StatusCode);
}

3. 测试Put接口的状态码

Put接口涉及Accepted、NotFound和InternalServerError三种场景,测试代码如下:

// Put接口测试集
[TestMethod]
public void PutReturnsAcceptedStatus()
{
    // Arrange
    var fakeStudentModel = new StudentModel { Id = 1, Name = "Updated Student" };
    var fakeStudent = new Student { Id = 1, Name = "Updated Student" };
    
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Returns(fakeStudent);
    mockRepository.Setup(x => x.Update(fakeStudent)).Returns(true); // 更新成功

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Put(fakeStudentModel);
    var contentResult = actionResult as NegotiatedContentResult<StudentModel>;

    // Assert
    Assert.IsNotNull(contentResult);
    Assert.AreEqual(HttpStatusCode.Accepted, contentResult.StatusCode);
    Assert.AreEqual(fakeStudentModel.Id, contentResult.Content.Id);
}

[TestMethod]
public void PutReturnsNotFoundWhenStudentDoesNotExist()
{
    // Arrange
    var fakeStudentModel = new StudentModel { Id = 999 };
    var fakeStudent = new Student { Id = 999 };
    
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Returns(fakeStudent);
    mockRepository.Setup(x => x.Update(fakeStudent)).Returns(false); // 更新失败(学生不存在)

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Put(fakeStudentModel);
    var notFoundResult = actionResult as NotFoundResult;

    // Assert
    Assert.IsNotNull(notFoundResult);
    Assert.AreEqual(HttpStatusCode.NotFound, notFoundResult.StatusCode);
}

[TestMethod]
public void PutReturnsExceptionResultWhenErrorOccurs()
{
    // Arrange
    var fakeStudentModel = new StudentModel();
    mockTransformer.Setup(x => x.TransformModelToEntity(fakeStudentModel)).Throws<Exception>();

    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Put(fakeStudentModel);
    var exceptionResult = actionResult as ExceptionResult;

    // Assert
    Assert.IsNotNull(exceptionResult);
    Assert.AreEqual(HttpStatusCode.InternalServerError, exceptionResult.StatusCode);
}

4. 测试Delete接口的状态码

Delete接口覆盖Ok、NotFound和InternalServerError三种场景:

// Delete接口测试集
[TestMethod]
public void DeleteReturnsOkStatus()
{
    // Arrange
    mockRepository.Setup(x => x.Delete(It.IsAny<int>())).Returns(true); // 删除成功
    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Delete(1);
    var okResult = actionResult as OkResult;

    // Assert
    Assert.IsNotNull(okResult);
    Assert.AreEqual(HttpStatusCode.OK, okResult.StatusCode);
}

[TestMethod]
public void DeleteReturnsNotFoundWhenStudentDoesNotExist()
{
    // Arrange
    mockRepository.Setup(x => x.Delete(It.IsAny<int>())).Returns(false); // 删除失败(学生不存在)
    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Delete(999);
    var notFoundResult = actionResult as NotFoundResult;

    // Assert
    Assert.IsNotNull(notFoundResult);
    Assert.AreEqual(HttpStatusCode.NotFound, notFoundResult.StatusCode);
}

[TestMethod]
public void DeleteReturnsExceptionResultWhenErrorOccurs()
{
    // Arrange
    mockRepository.Setup(x => x.Delete(It.IsAny<int>())).Throws<Exception>();
    var controller = new StudentController(mockRepository.Object, mockTransformer.Object);

    // Act
    IHttpActionResult actionResult = controller.Delete(1);
    var exceptionResult = actionResult as ExceptionResult;

    // Assert
    Assert.IsNotNull(exceptionResult);
    Assert.AreEqual(HttpStatusCode.InternalServerError, exceptionResult.StatusCode);
}

通用测试小技巧

  • 状态码验证方式:带内容的结果用NegotiatedContentResult<T>,无内容的状态码结果用StatusCodeResult或其子类(如NotFoundResult、OkResult)验证。
  • 异常测试:确保模拟依赖抛出异常时,控制器返回ExceptionResult且状态码为InternalServerError。
  • 内容验证:对带返回内容的结果(如Ok、Created、Accepted),一定要验证返回内容的业务字段是否符合预期,避免只测状态码忽略业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:30:49