ASP.NET Testing Api controller: Uri(Request.GetEncodedUrl()…) returns null

帅比萌擦擦* 提交于 2021-02-19 07:43:49

问题


I am testing an ASP.NET Core Api post method, but I get a System.NullReferenceException causing my test to fail.

The null exception appears when I try to return a Created()-ActionResult, like this:

return Created(new Uri(Request.GetEncodedUrl() + "/" + personDto.Id), personDto);

My personDto.Id nor the personDto is not null, but the result of the Uri() returns null. I have googled but not found a solution, but I believe I have to mock the Uri()-method in some way (I am new to testing and asp.net in general). The Api works well when testing it "live" against a SQL Server.

I am using Moq and NUnit to test, and below is part of my Setup and Test-methods:

public void SetUp()
{
    _mapper = GenerateConcreteInstance();

    _personService = new Mock<IPersonService>();

    _personService.Setup(ps => ps.Create(It.IsAny<Person>())).Verifiable();

    _controller = new PeopleController(_personService.Object, _mapper);
}

[Test]
public void CreatePerson_WhenCalled_IsNotNull()
{
    var personDto = new PersonDto()
    {
        Id = 3,
        Firstname = "Karl",
        Lastname = "Karlsson",
        City = "Oslo",
        Email = "karl.karlsson@test.com"
    };

    var result = _controller.CreatePerson(personDto);

    var createdResult = result as CreatedResult;

    Assert.IsNotNull(createdResult);
}

And my controller that I am trying to test:

[HttpPost]
public IActionResult CreatePerson(PersonDto personDto)
{
    if (!ModelState.IsValid)
        return BadRequest();

    var person = _mapper.Map<PersonDto, Person>(personDto);
    person.DateCreated = DateTime.Now;

    _personService.Create(person);
    _personService.Save();

    personDto.Id = person.Id;

    return Created(new Uri(Request.GetEncodedUrl() + "/" + personDto.Id), personDto);
}

How do I setup this test properly to avoid the null exception? Would appreciate any help on how to solve this problem, and pointers in general, if my test is not good in any other way.

Update

I have modifed the test like this. Am I on the right track?

public void CreatePerson_WhenCalled_IsNotNull()
{
    var personDto = new PersonDto()
    {
        Id = 3,
        Firstname = "Karl",
        Lastname = "Karlsson",
        City = "Oslo",
        Email = "karl.karlsson@test.com"
    };

    var request = new Mock<HttpRequest>();
    request.Setup(x => x.Headers).Returns(
        new HeaderDictionary {
        {"X-Requested-With", "XMLHttpRequest"}
    });


    var context = new Mock<HttpContext>();
    context.Setup(x => x.Request).Returns(request.Object);

    _controller.ControllerContext = new ControllerContext()
    {
        HttpContext = context.Object
    };

    var result = _controller.CreatePerson(personDto);

    var createdResult = result as CreatedResult;

    Assert.IsNotNull(createdResult);
}

回答1:


Request.GetEncodedUrl() extension relies on having a valid request.

/// <summary>
/// Returns the combined components of the request URL in a fully escaped form suitable for use in HTTP headers
/// and other HTTP operations.
/// </summary>
/// <param name="request">The request to assemble the uri pieces from.</param>
/// <returns>The encoded string version of the URL from <paramref name="request"/>.</returns>
public static string GetEncodedUrl(this HttpRequest request)
{
    return BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path, request.QueryString);
}

Source

Which will fail

if (scheme == null)
{
    throw new ArgumentNullException(nameof(scheme));
}

Source

There is no context or request associated with the shown example so I suggest providing a valid context with the necessary members populated for the test to be exercised as expected.

//...omitted for brevity

var httpContext = new DefaultHttpContext();
//http://localhost/example
httpContext.Request.Scheme = "http";
httpContext.Request.Host = new HostString("localhost");

//Controller needs a controller context 
var controllerContext = new ControllerContext() {
    HttpContext = httpContext,
};
//assign context to controller
_controller.ControllerContext = controllerContext;

//...omitted for brevity


来源:https://stackoverflow.com/questions/58613899/asp-net-testing-api-controller-urirequest-getencodedurl-returns-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!