WebApi action method returning null - c#

It's been a whole day and I can't able to find a solution.
My Controller's ActionMethod is working fine when it calls from PostMan.
But when I call it from my Unit Test Method, it keeps returning null.
Here is my code.
I already found an answer on StackOverflow:
https://stackoverflow.com/a/56498657/11425180
But this is not resolving my issue.
Here is my ActionMethod
[HttpPost("register")]
public async Task<IActionResult> RegisterUser([FromBody] CreateUserRequest request)
{
if (!ModelState.IsValid)
return BadRequest(ModelState);
try
{
// Map request with dto and give to service
CreateUserRequestDto createDto = _mapper.Map<CreateUserRequestDto>(request);
CreateUserResponseDto response = await _userService.CreateUser(createDto);
if (response.IsSuccess)
{
Success success = new Success(message: SuccessMessages.UserCreated, data: response);
return Ok(success);
}
Error error = new Error(message: ErrorMessages.UserRegistrationFailed, description: response.Error.Description);
return BadRequest(error);
}
catch (Exception ex)
{
return HandleException(ex);
}
}
Here is my test Class
public class MockAccountControllerTests
{
readonly UserController _accountController;
public MockAccountControllerTests()
{
Mock<IMapper> _mockMapper = new Mock<IMapper>();
Mockers.InitializeMappers(_mockMapper);
UserManager<AppUser> _mockUserManager = Mockers.MockUserManager<AppUser>().Object;
UserRepository _mockUserRepository = new Mock<UserRepository>(_mockUserManager, _mockMapper.Object).Object;
UserService _mockUserService = new Mock<UserService>(_mockUserRepository).Object;
_accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
}
[Fact]
public async Task RegisterUser_NullUserNamePassword_ThrowsException()
{
CreateUserRequest request = RequestHelpers.CreateUserRequest(null, null);
IActionResult result = await _accountController.RegisterUser(request);
ObjectResult badRequest = result as ObjectResult;
Assert.NotNull(badRequest);
Assert.True(badRequest is BadRequestObjectResult);
Assert.Equal(StatusCodes.Status400BadRequest, badRequest.StatusCode);
Assert.NotNull(badRequest.Value);
Assert.IsType<Error>(badRequest.Value);
}
}
At this line in my Test Method
var result = await _accountController.RegisterUser(request);
The result is null
I also tried to assign a value of BadRequest to a variable like this
var a = BadRequest("Test Message");
The a is also null in this case.
How this will be corrected?
Am I doing something wrong in my ActionMethod or TestMethod?
Kindly review.

This line is the culprit:
_accountController = new Mock<UserController>(_mockUserService, _mockMapper.Object).Object;
Don't mock your system under test, because then you're not testing your code, but simply whether Moq does what it's supposed to do. And it does: it returns default values (null for reference types) for method calls that aren't SetUp().
So instead initialize it to an actual instance of your controller:
_accountController = new UserController(_mockUserService, _mockMapper.Object);
See also: Test controller logic in ASP.NET Core on learn.microsoft.com.

The only possible explanation is that whatever the type of result, it's not derived from ObjectResult, so casting it to ObjectResult via as results in a null value being returned.
The thing is that, I don't see any output that returns something that doesn't derive from ObjectResult, except in your catch block where you're returning HandleException(ex). It's not clear what the type returned is here, so I can only assume that that's where your problem lies. In short, that needs to return an ObjectResult type. Things like BadRequestResult without Object in their names derive from StatusCodeResult, which shares no lineage with ObjectResult.
It's also worth mentioning that once you get past this assertion, your next will fail. Since you're casting whatever the result is to ObjectResult and saving it to badRequest, the assertion Assert.True(badRequest is BadRequestObjectResult) will always fail, because it will always be ObjectResult, not BadRequestObjectResult.

Related

Mock function not throwing exception in c# unit test

Here is my unit test method
[Fact]
public void DealerSmsStatusTestTest_MustReturnInternalServerErrorIfMockMethodFails()
{
//Arrange
Mock<DBClass.IDealer> mock = new Mock<DBClass.IDealer>();
var exception = FormatterServices.GetUninitializedObject(typeof(System.Data.SqlClient.SqlException));
mock.Setup(x => x.GetDealerStatus(new System.Net.Http.HttpRequestMessage()))
.Throws((System.Data.SqlClient.SqlException)exception);
DealerSettingController controller = new DealerSettingController(mock.Object);
//Act
var result = controller.DealerSmsStatus();
//Assert
/*I will do assertion here*/
}
And here is my controller method
public IHttpActionResult DealerSmsStatus()
{
try
{
var result = _dealer.GetDealerStatus(Request);
return Json(new Models.Response(
Models.ResponseMessages.Success,
result)
);
}
catch (System.Data.SqlClient.SqlException)
{
return InternalServerError();
}
catch (System.Exception ex)
{
Logger.Error(ex, ex.Message, ex.StackTrace);
return InternalServerError();
}
}
When i debug the test, GetDealerStatus() method should return SqlException instead it returns null. In controller method var result always getting null. Any suggestions appreciated why it is not working.I want to throw SqlException through GetDealerStatus().
Here is debug mode result value image
You should use It.IsAny<System.Net.Http.HttpRequestMessage>() instead of new System.Net.Http.HttpRequestMessage() at Setup. Because you configured your method for concrete instance of System.Net.Http.HttpRequestMessage, at test it's not the same.
It's probably the matcher x.GetDealerStatus(new System.Net.Http.HttpRequestMessage())
new System.Net.Http.HttpRequestMessage() creates a new instance of a HttpRequestMessage which will not be equal to the Request you're passing into GetDealerStatus in your SUT.
Normally you'd use something like:
x.GetDealerStatus(It.IsAny<System.Net.Http.HttpRequestMessage>())
or
It.Is<System.Net.Http.HttpRequestMessage>(x => whatever specific equality conditions you want to match on)
if you want to narrow the match condition from just 'any'

Why the method does not return custom exception message

I would like to an async method "UpdateAsync" return custom exception message when PutAsync method is invoked. What I do now is mock the class which is PutAsync belong to, and then I setup the method and give the parameter. I also use Throws to custom exception message.
The problem is when I run this
var result = await this.repository.UpdateAsync(new EndPoint(new Uri(testUrl), HttpMethod.Put), JObject.FromObject(new object()), this.exceptionProcessor);
The PutAsync keep running without return exception.
Here is the code.
Mock<RestClient> rc = new Mock<RestClient>();
rc.Setup(x => x.PutAsync(new Uri(testUrl), JObject.FromObject(new object()), new NameValueCollection()))
.Throws(new Exception("TestMessage"));
var result = await this.repository.UpdateAsync(new EndPoint(new Uri(testUrl), HttpMethod.Put), JObject.FromObject(new object()), this.exceptionProcessor);
Assert.IsTrue(result.ErrorMessages.GetValue(string.Empty).Equals("TestMessage"));
here is the main part of UpdateAsync, when process goes here, it will enter GetClient() first and then jump to Exception direct. This test was wrote using Shimes, but we don't want to use Shimes anymore, therefore I need to use another way to do.
public virtual async Task<GenericOperationResult<object>> UpdateAsync(EndPoint endpoint, JContainer obj, IExceptionProcessor exceptionProcessor, NameValueCollection headers){
if (endpoint.ActionMethod == HttpMethod.Put)
{
result = await this.GetClient().PutAsync(endpoint.Url, obj, headers);
}
else if (endpoint.ActionMethod == HttpMethod.Post)
{
result = await this.GetClient().PostAsync(endpoint.Url, obj, headers);
}
else
{
throw new ConfigurationException("Update supports only POST or PUT verbs. Check endpoint configuration.");
}
return new GenericOperationResult<object>(200, result);
}
You are instantiating new objects in your setup, which are different from the objects you are instantiating in your call to UpdateAsync, so they won't match and the Mock object won't throw the exception. You could instead setup the mock to throw the exception if objects of the correct types are passed in, with the Url param also checking it has the testUrl, for example:
rc.Setup(x => x.PutAsync(It.Is<Uri>(u => u.OriginalString == testUrl), It.IsAny<JObject>(), It.IsAny<NameValueCollection>())
.ThrowsAsync(new Exception("TestMessage"));

I want to check if the Correct BusinessException is thrown with unit test?

This is my method in the controller.
public ActionResult DeleteModelAliasData(string alias)
{
if (!ModelState.IsValid)
{
ModelState.LogModelStateError();
throw new BusinessException("COMMON_ERROR");
}
var response = _vehicleDataBusinessService.DeleteModelAliasData(alias);
return Json(response);
}
I am new at unit testing and I want to write the unit test that when the "!ModelState.IsValid" then the exception is thrown, I want to check that is it the correct exception which I Wanted?
You can do the same as shown in below code.
var ex = Assert.Throws<BusinessException>(() => controller.DeleteModelAliasData(alias));
Assert.That(ex.Message, Is.EqualTo("COMMON_ERROR"));
Reference: NUnit Exception Asserts
Update:
[Test]
public void TestDeleteModelAliasData()
{
// Get your controller instance - you know it better how to instantiate
var controller = GetControllerInstance();
// Add error message to ModelState
controller.ModelState.AddModelError("PropertyName", "Error Message");
var alias = "sampleAlias";
// As ModelState is having an Error, the method should throw BusinessException
var ex = Assert.Throws<BusinessException>(() => controller.DeleteModelAliasData(alias));
// Exception is raised, assert the message if you want
Assert.That(ex.Message, Is.EqualTo("COMMON_ERROR"));
}
The default value for ModelState.IsValid is true when the model state dictionary is empty.
That would mean that in order for the method under test to flow in the desired path you would need to make sure that the model state behaves as expected.
This can be done by adding a model error to the model state
For example
//Arrange
//...initialize controller and its dependencies
//add model error to force IsValid to be false.
controller.ModelState.AddModelError("PropertyName", "Error Message");
var alias = string.Empty;
var expectedErrorMessage = "COMMON_ERROR";
//Act
Action act = () => controller.DeleteModelAliasData(alias);
//Assert
Assert.That(act, Throws.TypeOf<BusinessException>()
.With.Message.EqualTo(expectedErrorMessage));
You would then assert that the expected exception is thrown with the expected values.
Reference ThrowsConstraint

Whats tests would sufficiently Unit Test a "Create" controller method in MVC?

I want to test this (Controller Method) :
public async Task<IActionResult> Create(SecurityQuestionViewModel securityQuestion)
{
if (ModelState.IsValid)
{
SecurityQuestion dataModel = new SecurityQuestion();
dataModel.questionText = securityQuestion.QuestionText;
await _securityRepository.AddAsync(dataModel);
return RedirectToAction("Index");
}
else
{
return View();
}
}
My unit test (so far) looks like this ?
public async Task ModelContainsNewObjectAfterCreate()
{
//Arrange
_repository = new Mock<ISecurityQuestionRepository>();
_repository.Setup(repo => repo.GetAllAsync()).Returns(Task.FromResult(securityQuestion()));
_controller = new SecurityQuestionsController(_repository.Object, _mapper);
SecurityQuestion dataModel = new SecurityQuestion();
dataModel.questionText = "This is the new added question";
SecurityQuestionViewModel sqvm = new SecurityQuestionViewModel();
sqvm.QuestionText = dataModel.questionText;
//Act
var result = await _controller.Create(sqvm);
//Assert
var viewResult = Assert.IsType<RedirectToActionResult>(result);
_repository.Verify(r => r.AddAsync(dataModel), Times.Once);
}
The viewResult passes.
The _repository verify does not.
It feels like I need to verify that the AddAsync method ran (would add a record to the existing repository). Perhaps my setup is wrong
It also feels like I need to validate the number of "questions" in the repository after the AddAsync method ran.
I am trying to understand what would constitute an adequate test and how to simulate the "Add" with the Moq.
Any insight would be appreciated.
This Post seems close to what I want.
You can test only following things in your action:
The case when the model is valid.
The case when the model is invalid.
There are only two cases. If the first case is satisfied you can verify that AddAsync() is executed with any parameter which is type SecurityQuestion.
You can mock AddAsync() like this:
repository.Setup(r => r.AddAsync(It.IsAny<SecurityQuestion>())
.Returns(Task.FromResult(false));
And verify:
repository.Verify(r => r.AddAsync(It.IsAny<SecurityQuestion>()), Times.Once);
That is all which you can!
You cannot mock SecurityQuestion model because it uses new keyword and your code which try to mock should be removed.
This is all you need to do because your entire logic is if/else statement. Everything else will be executed normally. Only another thing which can behave unexpectedly is if AddAsync() throws an exception.
The verify fails because the model was created within the method under test so it does not match. what you can do is use the It.Is with a predicate that matches the model properties
_repository.Verify(r => r.AddAsync(It.Is<SecurityQuestion>(m => m.questionText == dataModel.questionText)), Times.Once);

HttpClient.GetAsync immediately throws TaskCanceledException

I had a working code that was returning something from my CommonRestClient(which is simple wrapper for HttpClient):
public async Task<IActionResult> Index()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
var result = await client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
return View(result);
}
}
It worked fine and i was happy. Until I decide to move my code from view in another class, which should incapsulate entire REST logic and provide an OOP API.
So now my index looks like:
public async Task<IActionResult> Index()
{
var nodeInfoContracts = await _configManager.GetNodesList();
return View(nodeInfoContracts);
}
where GetNodesList is
public ConfiguredTaskAwaitable<List<NodeInfoContract>> GetNodesList()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
return client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
}
}
It's clear that provided codes are equal.
But now it always throws an exception when I try to get a result. In my GetAsync method it fails on following line with TaskCanceledException:
var response = await _client.GetAsync(url).ConfigureAwait(false);
But it's interestring: when I place a breakpoint on this line and step over its works fine. So here we have race condition or similar.
Why am I getting it? I tried to place CondigureAwait false/true, combining some code, but it always throws an error when breakpoints are off. I checked timeout which is several minutes, it can't cause this error.
In the second code snippet the client is disposed before the IO completed. Use the first form.

Categories

Resources