D3v
D3v

Reputation: 345

How to create mock HTTP post request with a JSON body using Moq

I'm trying to do basically what the title says in order to unit test my api controller, but I have problems finding the proper way and can't afford spending too much time on this. Here is my code.

[TestMethod]
public void Should_return_a_valid_json_result()
{
    // Arrange
    Search search = new Search();
    search.Area = "test";
    string json = JsonConvert.SerializeObject(search);

    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();

    request.Setup(r => r.HttpMethod).Returns("POST");
    request.Setup(r => r.InputStream.ToString()).Returns(json);

    context.Setup(c => c.Request).Returns(request.Object);

    var controller = new UserController();
    controller.ControllerContext = new HttpControllerContext() {  RequestContext = context };

   //more code

}

Last line returns Error CS0029 Cannot implicitly convert type 'Moq.Mock System.Web.HttpContextBase' to 'System.Web.Http.Controllers.HttpRequestContext'.

I am also not sure about the Moq syntax I should use, other questions,examples and Moq Documentation didn't help me much.

Upvotes: 7

Views: 17572

Answers (3)

Sapnandu
Sapnandu

Reputation: 640

I'm using this approach

My API controller

[Route("[controller]")]
[ApiController]
public class FetchLeadStatusController : ControllerBase
{
    private readonly IFtchDgLdStsExecution _ftchDgLdStsExecution;            
    public FetchLeadStatusController(IFtchDgLdStsExecution ftchDgLdStsExecution)
    {
        this._ftchDgLdStsExecution = ftchDgLdStsExecution;
    }
[HttpPost]
public async Task<IActionResult> Post()
{
   try
    {
       StreamReader requestReader = new StreamReader(Request.Body);
       dynamic request = JObject.Parse(await requestReader.ReadToEndAsync());
       FtchDgLdStsReturn Casetatus = await _ftchDgLdStsExecution.ValidateFtchDgLdSts(request);    
          return Ok(Casetatus); 

     }
     catch (Exception ex)
     {
        return BadRequest();

     }
}

My test class

[TestClass]
public class FetchLeadStatusControllerTest
{
    private Mock<IFtchDgLdStsExecution> _FtchDgLdStsExecution;
    private Fixture _fixture;
    private FetchLeadStatusController _controller;

    public FetchLeadStatusControllerTest()
    {
       _fixture = new Fixture();
       _FtchDgLdStsExecution = new Mock<IFtchDgLdStsExecution>();
       _controller = new FetchLeadStatusController(_FtchDgLdStsExecution.Object);
    }

    [TestMethod]
    public async Task Post_FetchDigiLeadStatus_ReturnOK()
    {
        var request_body = new RequestBody();
        request_body.LeadID = "1000078";
        var json = JsonConvert.SerializeObject(request_body);

        var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
        var httpContext = new DefaultHttpContext()
            {
                Request = { Body = stream, ContentLength = stream.Length }
            };
        var controllerContext = new ControllerContext { HttpContext = httpContext };

        var ftch_Return = _fixture.Create<FtchDgLdStsReturn>();

        _FtchDgLdStsExecution.Setup(x => x.ValidateFtchDgLdSts(json)).ReturnsAsync(ftch_Return);

        _controller.ControllerContext = controllerContext;

        var result = await _controller.Post();
            Assert.IsNotNull(result);
        }    

    }

Upvotes: 0

ladeangel
ladeangel

Reputation: 261

I'm using this approach

var json = JsonConvert.SerializeObject(request);
var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var httpContext = new DefaultHttpContext()
                  {
                       Request = { Body = stream, ContentLength = stream.Length }
                  };
var controllerContext = new ControllerContext { HttpContext = httpContext };            

var controller = new Your_Controller(logic, logger) { ControllerContext = controllerContext };

Upvotes: 15

Nkosi
Nkosi

Reputation: 247521

No need for mock here if the intention is just to pass a request.

[TestMethod]
public void Should_return_a_valid_json_result() {
    // Arrange
    var search = new Search();
    search.Area = "test";
    var json = JsonConvert.SerializeObject(search);

    var request = new HttpRequestMessage();
    request.Method = HttpMethod.Post;
    request.Content = new StringContent(json);

    var controller = new UserController();
    controller.Request = request;

    //more code

}

Upvotes: 8

Related Questions