Reputation: 415
I am working on a unit test project to test Web API v2 with IHttpActionResponse
as return type.
I am not able to find out a way to test all the status codes with IHttpActionResponse
return type. Especially post need to test http status code created. Here I created some of the tests for Get
and GetById
also. Let me know how we can test all the status codes returning IHttpActionResponse
.
API controller code
public class StudentController : ApiController
{
IRepository<Student> repository;
ITransformers<StudentModel, Student> transformer;
public StudentController(IRepository<Student> studentRepository, ITransformers<StudentModel, Student> studentTransformer)
{
repository = studentRepository;
transformer = studentTransformer;
}
[HttpGet]
public IHttpActionResult Get()
{
IEnumerable<Student> students = null;
try
{
students = repository.Get();
if (students.Count<Student>() > 0)
{
return Ok(students);
}
else
{
return StatusCode(HttpStatusCode.NoContent);
//return Content(HttpStatusCode.NoContent, students);
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpGet]
public IHttpActionResult Get(int Id)
{
Student student = null;
try
{
student = repository.GetById(Id);
if (student != null)
{
return Ok(student);
}
else
{
return NotFound();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpPost]
public IHttpActionResult Post(StudentModel studentModel)
{
try
{
Student student = transformer.TransformModelToEntity(studentModel);
int result = repository.Save(student);
if (result > 0)
{
student.Id = result;
return Content(HttpStatusCode.Created, student);
}
else
{
return InternalServerError();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpPut]
public IHttpActionResult Put(StudentModel studentModel)
{
try
{
Student student = transformer.TransformModelToEntity(studentModel);
if (repository.Update(student))
{
return Content(HttpStatusCode.Accepted, studentModel);
}
else
{
return NotFound();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
[HttpDelete]
public IHttpActionResult Delete(int Id)
{
try
{
if(repository.Delete(Id))
{
return Ok();
}
else
{
return NotFound();
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}
}
My test class code
[TestClass]
public class StudentServiceTest
{
static Mock<ITransformers<StudentModel, Student>> mockTransformer;
static Mock<IRepository<Student>> mockRepository;
[ClassInitialize]
public static void ClassInit(TestContext context)
{
mockTransformer = new Mock<ITransformers<StudentModel, Student>>();
mockRepository = new Mock<IRepository<Student>>();
}
//GetAll Tests
[TestMethod]
public void GetReturnsAllStudents()
{
// Arrange
IEnumerable<Student> fakeStudents = GetFakeStudents();
mockRepository.Setup(x => x.Get()).Returns(fakeStudents);
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get();
var contentResult = actionResult as OkNegotiatedContentResult<IEnumerable<Student>>;
// Assert
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Content);
Assert.IsInstanceOfType(contentResult, typeof(OkResult));
Assert.AreEqual(3, contentResult.Content.Count());
}
[TestMethod]
public void GetReturnsNoContent()
{
// Arrange
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get();
StatusCodeResult statusCodeResult = actionResult as StatusCodeResult;
//Assert
Assert.IsNotNull(statusCodeResult);
Assert.AreEqual<HttpStatusCode>(HttpStatusCode.NoContent, statusCodeResult.StatusCode);
}
[TestMethod]
public void GetReturnsException()
{
// Arrange
mockRepository.Setup(x => x.Get()).Throws<Exception>();
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get();
//Assert
Assert.IsNotNull(actionResult);
Assert.IsInstanceOfType(actionResult, typeof(ExceptionResult));
}
//End of tests GetAll
//GetById Tests
[TestMethod]
public void GetByIdReturnsStudent()
{
// Arrange
IEnumerable<Student> fakeStudents = GetFakeStudents();
mockRepository.Setup(x => x.GetById(It.IsAny<int>())).Returns(fakeStudents.FirstOrDefault());
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get(It.IsAny<int>());
var contentResult = actionResult as OkNegotiatedContentResult<Student>;
// Assert
Assert.IsNotNull(contentResult);
Assert.IsNotNull(contentResult.Content);
Assert.AreEqual(1, contentResult.Content.Id);
}
[TestMethod]
public void GetByIdReturnsNotFound()
{
// Arrange
Student student = null;
mockRepository.Setup(x => x.GetById(It.IsAny<int>())).Returns(student);
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get(It.IsAny<int>());
// Assert
Assert.IsNotNull(actionResult);
Assert.IsInstanceOfType(actionResult, typeof(NotFoundResult));
}
[TestMethod]
public void GetByIdReturnsException()
{
// Arrange
mockRepository.Setup(x => x.Get()).Throws<Exception>();
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Get(It.IsAny<int>());
//Assert
Assert.IsNotNull(actionResult);
Assert.IsInstanceOfType(actionResult, typeof(ExceptionResult));
}
//End of GetById tests
}
Testing post for checking status code 201
[TestMethod]
public void PostReturnsSuccess()
{
// Arrange
mockRepository.Setup(x => x.Save(It.IsAny<Student>())).Returns(1);
mockTransformer.Setup(x => x.TransformModelToEntity(It.IsAny<StudentModel>())).Returns(GetFakeStudents().FirstOrDefault());
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Post(It.IsAny<StudentModel>());
var createdResult = actionResult as CreatedNegotiatedContentResult<Student>;
//var createdResult = actionResult as CreatedAtRouteNegotiatedContentResult<Student>;
//Assert
Assert.IsNotNull(actionResult);
Assert.IsNotNull(createdResult.Content);
Assert.AreEqual(1, createdResult.Content.Id);
}
Tried to use CreatedNegotiatedContentResult
and CreatedAtRouteNegotiatedContentResult
and compare the status codes but my actionResult
has exceptions for Formatters, ContentNegotiation and Request Properties and gets a null object in createdResult
.
Let me know how to check for the status code 201?
Updated for mocking BadRequest from CustomFilter
Modelstatevalidationfilter
public class ModelStateValidationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);
}
}
}
Test Method for BadRequest
[TestMethod]
public void PostReturnsBadRequest()
{
// Arrange
//var mockFilter = new Mock<ModelStateValidationFilter>().Setup(x=>x.OnActionExecuting(It.IsAny<HttpActionContext>()))
var controller = new StudentController(mockRepository.Object, mockTransformer.Object);
// Act
IHttpActionResult actionResult = controller.Post(new StudentModel { Id = 0, FirstName = "Raju", LastName = "", CourseId = 0 });
var badResult = actionResult as NegotiatedContentResult<Student>;
//Assert
Assert.IsNotNull(actionResult);
Assert.IsInstanceOfType(actionResult, typeof(BadRequestErrorMessageResult));
//TODO: Check for status code bad request and
Assert.IsNotNull(badResult.Content);
Assert.AreEqual(HttpStatusCode.Created, badResult.StatusCode);
}
where in model lastname is required so API is returning BadRequest. But how to mock this behaviour in unit test?
Upvotes: 0
Views: 9610
Reputation: 247521
The Post(StudentModel studentModel)
method is returning a NegotiatedContentResult<T>
on success
return Content(HttpStatusCode.Created, student);
yet the PostReturnsSuccess
test tries to cast it to
var createdResult = actionResult as CreatedNegotiatedContentResult<Student>;
//var createdResult = actionResult as CreatedAtRouteNegotiatedContentResult<Student>;
Either update the test to match what is expected from the action and then check the expected status code
// Act
IHttpActionResult actionResult = controller.Post(It.IsAny<StudentModel>());
var createdResult = actionResult as NegotiatedContentResult<Student>;
//Assert
Assert.IsNotNull(actionResult);
Assert.IsNotNull(createdResult.Content);
Assert.AreEqual(1, createdResult.Content.Id);
Asssert.AreEqual(HttpStatusCode.Created, createdResult.StatusCode); // <-- check status
or update the action to use one of the Created
related methods of ApiController
which would have set the status code when invoked at run time.
Upvotes: 2