问题
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