Issue Moq'ing HttpResponseMessage - c#

I have the following Method:
public async Task<SecurityRoleDeleteResult> DeleteSecurityRoleByRoleId(int securityRoleId)
{
string url = $"{_housingDataSecurityConfiguration.HousingDataSecurityWebApiUrl}SecurityRoles/Delete";
HttpResponseMessage message = _apiClientService.Post(url, securityRoleId);
if (message.StatusCode == HttpStatusCode.InternalServerError)
{
return SecurityRoleDeleteResult.ErrorOccurred;
}
int intResult = 0;
var apiResult = await message.Content.ReadAsStringAsync();
if (int.TryParse(apiResult, out intResult))
{
return (SecurityRoleDeleteResult)intResult;
}
else
{
return SecurityRoleDeleteResult.ErrorOccurred;
}
}
I'm now trying to write a unit test for it and so far have:
[Test]
public async Task DeleteSecurityRoleByRoleId()
{
_mockApiClientService.Setup(a => a.Post(It.IsAny<string>(), It.IsAny<int>()))
.Returns(new HttpResponseMessage {StatusCode = HttpStatusCode.OK});
SecurityRoleDeleteResult result = await _securityRoleService.DeleteSecurityRoleByRoleId(It.IsAny<int>());
Assert.AreEqual(SecurityRoleDeleteResult.Success, result);
}
The issue here is that when running the test in the _securityRoleService.DeleteSecurityRoleByRoleId method at the point I try to set var apiResult message.content is null, because in this instance I'm only mocking so crashes.
How can I mock this out so that my test will work?

I figured out my issue. Rather than delete my question, I thought I'd post my change to the test. Basically I hadn't mocked the content.
HttpContent content = new StringContent("4");
_mockApiClientService.Setup(a => a.Post(It.IsAny<string>(), It.IsAny<int>()))
.Returns(new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Content = content });
So depending on the content type you may want to have returned you may need to change the type of content.

Related

How to Unit test WEB API Controller Exception using Moq

How to Unit test IHttpActionResult Exception InternalServerError with status code 500 and message
[HttpGet]
public async Task<IHttpActionResult> Get(Guid myId)
{
try
{
var myaccount = await _myaccountService.GetMyAccount(myId);
return Ok(myaccount);
}
catch (Exception ex)
{
return InternalServerError();
}
}
Did try with Test method
[TestMethod]
public async Task GeMyAccount_WhenThrowsException_ReturnsServerError()
{
// Arrange
var exception = new Exception("Internal Server Error");
var expectedResult = new List<MyAccount>
{
new MyAccount
{
Id = "1",
Name = "Name1"
},
new MyAccount
{
Id = "2",
Name = "Name2"
},
};
var myId = new Guid();
//Act
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService.Setup(mock =>
mock.GetMyAccount(myId)).Throws(exception).Verifiable();
var controller = new MyAccountController(mockMyAccountService.Object);
//Assert
var actualResult = (await controller.Get(myId) as
OkNegotiatedContentResult<MyAccount>).Content;
?? var result = actualResult as ObjectResult;
?? Assert.AreEqual(StatusCodes.Status500InternalServerError, result.StatusCode);
?? Assert.AreEqual("Internal Server Error ", result.Value);
mockMyAccountService.Verify(b => b.GetMyAccount(myId));
}
Not sure how to get the Exception and status code 500 using Moq.
As it was said by Nkosi the exception is swallowed by the try-catch block so you are not able to make any assertion against the exception.
But you can (and should) make assertion against the returned object.
[TestMethod]
public async Task GivenAFaultyMyAccountService_WhenICallGet_ThenItReturnsAnInternalServerError()
{
//Arrange
var expectedException = new Exception("Something went wrong");
var mockMyAccountService = new Mock<IMyAccountService>();
mockMyAccountService
.Setup(svc => svc.GetMyAccount(It.IsAny<Guid>()))
.Throws(expectedException);
var sut = new MyAccountController(mockMyAccountService.Object);
//Act
var actualResult = await sut.Get(Guid.NewGuid());
//Assert
Assert.IsInstanceOfType(actualResult, typeof(InternalServerErrorResult));
}
I've made the following changes to your test:
I've renamed your test to align with the Given-When-Then structure
In this test case I'm only focusing on a single situation when the underlying dependency is malfunctioning, so I've get rid of everything which is related to the happy path
The happy path should have a separate test case
I've made the mock Setup more generic by replacing the myId parameter to It.IsAny<Guid>()
I've also replaced the new Guid() to Guid.NewGuid() because the former would create an empty uuid, while the later will generate a new uuid
I've removed the Verifiable call because it is not really needed here
The Act phase is when you make the actual call against a given method, not when you are constructing the controller, so I've moved the comment to the right place
I've changed the variable name controller to sut, which stands for the System Under Test
I've replaced your hard to read assessment logic to a simple type check
InternalServerError returns an InternalServerErrorResult
MSTest's Assert class has a method called IsInstanceOf, which makes the type check more convenient
Take a look at this code
[Fact]
public async Task Test1()
{
//arrange
//prepare your data for test
//act
async Task action()
{
//run your sut action
}
//assert
var exception = await Assert.ThrowsAsync<Exception>(action);
Assert.Equal("Internal Server Error", exception.Message);
}

How to test a controller POST method which returns no data in response content in .NET Core 3.1?

i am new to integration tests. I have a controller method which adds a user to the database, as shown below:
[HttpPost]
public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserRequest request)
{
try
{
var command = new CreateUserCommand
{
Login = request.Login,
Password = request.Password,
FirstName = request.FirstName,
LastName = request.LastName,
MailAddress = request.MailAddress,
TokenOwnerInformation = User
};
await CommandBus.SendAsync(command);
return Ok();
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
As you have noticed my method returns no information about the user which has been added to the database - it informs about the results of handling a certain request using the status codes. I have written an integration test to check is it working properly:
[Fact]
public async Task ShouldCreateUser()
{
// Arrange
var createUserRequest = new CreateUserRequest
{
Login = "testowyLogin",
Password = "testoweHaslo",
FirstName = "Aleksander",
LastName = "Kowalski",
MailAddress = "akowalski#onet.poczta.pl"
};
var serializedCreateUserRequest = SerializeObject(createUserRequest);
// Act
var response = await HttpClient.PostAsync(ApiRoutes.CreateUserAsyncRoute,
serializedCreateUserRequest);
// Assert
response
.StatusCode
.Should()
.Be(HttpStatusCode.OK);
}
I am not sure is it enough to assert just a status code of response returned from the server. I am confused because, i don't know, shall i attach to assert section code, which would get all the users and check does it contain created user for example. I don't even have any id of such a user because my application finds a new id for the user while adding him/her to the database. I also have no idea how to test methods like that:
[HttpGet("{userId:int}")]
public async Task<IActionResult> GetUserAsync([FromRoute] int userId)
{
try
{
var query = new GetUserQuery
{
UserId = userId,
TokenOwnerInformation = User
};
var user = await QueryBus
.SendAsync<GetUserQuery, UserDto>(query);
var result = user is null
? (IActionResult) NotFound(new
{
Message = (string) _stringLocalizer[UserConstants.UserNotFoundMessageKey]
})
: Ok(user);
return result;
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
I believe i should somehow create a user firstly in Arrange section, get it's id and then use it in Act section with the GetUserAsync method called with the request sent by HttpClient. Again the same problem - no information about user is returned, after creation (by the way - it is not returned, because of my CQRS design in whole application - commands return no information). Could you please explain me how to write such a tests properly? Have i missed anything? Thanks for any help.
This is how I do it:
var response = (CreatedResult) await _controller.Post(createUserRequest);
response.StatusCode.Should().Be(StatusCodes.Status201Created);
The second line above is not necessary, just there for illustration.
Also, your response it's better when you return a 201 (Created) instead of the 200(OK) on Post verbs, like:
return Created($"api/users/{user.id}", user);
To test NotFound's:
var result = (NotFoundObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status404NotFound);
The NotFoundObjectResult assumes you are returning something. If you are just responding with a 404 and no explanation, replace NotFoundObjectResult with a NotFoundResult.
And finally InternalServerErrors:
var result = (ObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status500InternalServerError);
You can use integrationFixture for that using this NuGet package. This is an AutoFixture alternative for integration tests.
The documented examples use Get calls but you can do other calls too. Logically, you should test for the status code (OkObjectResult means 200) value and the response (which could be an empty string, that is no problem at all).
Here is the documented example for a normal Get call.
[Fact]
public async Task GetTest()
{
// arrange
using (var fixture = new Fixture<Startup>())
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var controller = fixture.Create<SearchEngineController>();
// act
var response = await controller.GetNumberOfCharacters("Hoi");
// assert
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
Assert.Equal(8, ((OkObjectResult)response.Result).Value);
}
}
}
private void SetupStableServer(FluentMockServer fluentMockServer, string response)
{
fluentMockServer.Given(Request.Create().UsingGet())
.RespondWith(Response.Create().WithBody(response, encoding: Encoding.UTF8)
.WithStatusCode(HttpStatusCode.OK));
}
In the example above, the controller is resolved using the DI described in your Startup class.
You can also do an actual REST call using using Refit. The application is self hosted inside your test.
using (var fixture = new RefitFixture<Startup, ISearchEngine>(RestService.For<ISearchEngine>))
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var refitClient = fixture.GetRefitClient();
var response = await refitClient.GetNumberOfCharacters("Hoi");
await response.EnsureSuccessStatusCodeAsync();
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
}
}

Async, await and Task works in debug mode only

The code below begins with the first line calling 'LoadNames' from a .net page. If I'm not in debug mode the interviews variable is set to null. If I add a debug point there and step through it gets a value from the api.
It was getting interviews in UAT. I'm pointing it now at LIVE.
I'm thinking it's likely something unresolved asynchronously. The old api being slower probably made it appear like it was working, and adding debug will slow it down making it appear correct too.
Page.RegisterAsyncTask(new PageAsyncTask(LoadNames));
private async Task LoadNames()
{
VideoInterviewRepository videoRepository = await Repository.CreateClient();
IEnumerable<Api> interviews = await Repository.GetEntityList<Api>(EndPoints);
CODE HERE RUNS BUT FAILS BECAUSE THE ABOVE CODE RETURNS NULL
var interviewList = interviews.ToDictionary(o => o.id, o => o.name);
}
public static Task<VideoInterviewRepository> CreateClient()
{
var videoInterviewRepository = new VideoInterviewRepository();
return videoInterviewRepository.InitializeClient();
}
private async Task<VideoInterviewRepository> InitializeClient()
{
client = VideoInterviewHttpClient.GetClient(VideoInterviewEndPoints.baseUrl);
var bearer = await Authenticate.GetBearerTokenAsync(client);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer);
return this;
}
public static async Task<string> GetBearerTokenAsync(HttpClient client)
{
var bearerResult = await client.SendAsync(requestToken);
var bearerData = await bearerResult.Content.ReadAsStringAsync();
bearerToken = JObject.Parse(bearerData)["access_token"].ToString();
}
public async Task<IEnumerable<T>> GetEntityList<T>(string path)
{
IEnumerable<T> model = await GetAndParseApiResponse<IEnumerable<T>>(path);
return model;
}
private async Task<T> GetAndParseApiResponse<T>(string path)
{
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
model = JsonConvert.DeserializeAnonymousType<T>(content, model);
}
return model;
}
I found the bug! All the async and awaits and Tasks were correct. The 3rd party didn't register the token on their end fast enough which is why by stepping through I caused a delay. I should have handled response.IsSuccessStatusCode.

Assert for empty content in 200 Http Response

I have a simple Web Api method which returns a list. I decided as a general project rule, that if the list is empty for a particular userId, we return an Ok() method with empty content.
My web api method looks like following:
[Route("")]
[HttpGet]
public IHttpActionResult GetPersonalList()
{
var result = _facade.Get(_userContext.Get());
if (result == null)
return Ok(); //here is the point
return Ok(new PersonalExpensesReportViewModel(result));
}
Trying to make a 100% of coverage of this method, I wanted to test the scenario that I mentioned, but I could not achieve how to write the assert for the empty content.
[TestMethod]
public void GetPersonalList_NoContent_Ok()
{
//Arrange
_facade.Setup(x => x.Get(_userContext.Object.GetPersonnelNumber(), null)).Returns((PersonalExpensesReport)null);
//Act
var result = _controller.GetPersonalList();
//Assert
var negociatedResult = result as OkResult;
Assert.IsNotNull(result);
// ?? I want something like Assert.IsNull(negociatedResult.Content)
}
Being that I don't have a certain type to make result as OkNegotiatedContentResult which expects T type to be instantiated, I thought about cast as OkResult, but I don't have the 'Content' property in this class.
Does someone know how to proceed in this cases?
Please try to use OkNegotiatedContentResult<T> like:
var result = _controller.GetPersonalList();
var response = result as OkNegotiatedContentResult<PersonalExpensesReportViewModel>;
Assert.IsNotNull(response);
var content = response.Content;
Assert.AreEqual(5, content.Count());
[TestMethod]
public void GetPersonalList_NoContent_Ok()
{
var serviceresponse = new yourresponseobject<yourmodel>{
Message = "what ever response";
Data = null;
};
var service = new Mock<youserviceInterface>(MockBehavior.Strict);
service.Setup(x => x.GetPersonalList()(It.IsAny<string>())).ReturnsAsync(serviceResponse); /// for number of parameters in controller method, add It.IsAny<string>()
//Arrange
_facade.Setup(x => x.Get(_userContext.Object.GetPersonnelNumber(), null)).Returns((PersonalExpensesReport)null);
//Act
var result = _controller.GetPersonalList();
//Assert
var negociatedResult = result as Object;
Assert.IsNotNull(result.value);
Assert.AreEqual(200,result.negociatedResult.statuscode);
}

How do I unit test requests against SSL-only Web Api Controller?

I have a unit test which uses the OWIN TestServer class to host my Web Api ApiController classes for testing.
I first wrote the unit test when the REST API did not have the HTTPS (SSL) requirement baked into the Controller itself.
My unit test looked something like this:
[TestMethod]
[TestCategory("Unit")]
public async Task Test_MyMethod()
{
using (var server = TestServer.Create<TestStartup>())
{
//Arrange
var jsonBody = new JsonMyRequestObject();
var request = server.CreateRequest("/api/v1/MyMethod")
.And(x => x.Method = HttpMethod.Post)
.And(x => x.Content = new StringContent(JsonConvert.SerializeObject(jsonBody), Encoding.UTF8, "application/json"));
//Act
var response = await request.PostAsync();
var jsonResponse =
JsonConvert.DeserializeObject<JsonMyResponseObject>(await response.Content.ReadAsStringAsync());
//Assert
Assert.IsTrue(response.IsSuccessStatusCode);
}
}
Now that I've applied the attribute to enforce HTTPS, my unit test fails.
How do I fix my test so that, all things being equal, the test passes again?
To fix this unit test, you need to change the base address for the TestServer.
Once the server has been created set the BaseAddress property on the created object to use an "https" address. Remember the default BaseAddress value is http://localhost.
In which case, you can use https://localhost.
The changed unit test would look as follows:
[TestMethod]
[TestCategory("Unit")]
public async Task Test_MyMethod()
{
using (var server = TestServer.Create<TestStartup>())
{
//Arrange
server.BaseAddress = new Uri("https://localhost");
var jsonBody = new JsonMyRequestObject();
var request = server.CreateRequest("/api/v1/MyMethod")
.And(x => x.Method = HttpMethod.Post)
.And(x => x.Content = new StringContent(JsonConvert.SerializeObject(jsonBody), Encoding.UTF8, "application/json"));
//Act
var response = await request.PostAsync();
var jsonResponse =
JsonConvert.DeserializeObject<JsonMyResponseObject>(await response.Content.ReadAsStringAsync());
//Assert
Assert.IsTrue(response.IsSuccessStatusCode);
}
}

Categories

Resources