如何测试返回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
相关产品推荐
相关产品推荐

