For some reason, I am having troubles making a unit test for the following in C#
[Route("api/Orders/{orderID:int}/Items")]
public OrderItemsDTO Get(int orderID)
{
if (_orderItemsService.Get(orderID).Items.Count() == 0)
{
throw new HttpResponseException(
Request.CreateErrorResponse(HttpStatusCode.NotFound, String.Format("Order {0} not found.", orderID)));
}
return _orderItemsService.Get(orderID);
}
I have a unit test running correctly for an Async Add which is what I'm using to Post that I was trying to base my unit test off of with some tweaks I thought it would work, but it doesn't. the following is what I thought should work:
private OrderItemsController _testSubject;
private Mock<IOrderItemsService> _moqOrderItemsService = new Mock<IOrderItemsService>();
[TestInitialize]
public void TestInitialize()
{
_testSubject = new OrderItemsController(_moqOrderItemsService.Object);
}
[TestMethod]
[ExpectedException(typeof(HttpResponseException))]
public async Task ThrowHttpResponseExceptionWhenThereIsAValidationException()
{
_moqOrderItemsService.Setup(ois => ois.Get(It.IsAny<int>()))
.Throws(new ValidationException("test"));
try
{
_testSubject.Get(17);
}
catch(HttpResponseException ex)
{
Assert.IsNotNull(ex.Response);
Assert.AreEqual(HttpStatusCode.NotFound, ex.Response.StatusCode);
throw;
}
}
You set up order item service mock to throw ValidationException when it is called with any id. Then you are expecting controller to throw HttpResponseException which is not true - you will have same exception as you throw from service.
You should setup service to return some object (you didn't provide definition of service interface and types which it returns) with empty Items property:
_moqOrderItemsService.Setup(ois => ois.Get(It.IsAny<int>()))
.Returns(/* some object with empty Items property */);
Now in controller you will go to throwing HttpResponseException path.
Side note: why are you throwing exceptions instead of returning something like Content(HttpStatusCode.NotFound, "Message")? You even can create base controller with method IHttpActionResult NotFound(string message) which will do this for you.
I would suggest not testing the Web API controller, rather test the _orderItemsService and mock out whatever repository you are using in the service. You can assert that the OrderItemsDTO is not null.
Well according to Microsoft testing controllers is best practice: https://learn.microsoft.com/en-us/aspnet/web-api/overview/testing-and-debugging/unit-testing-controllers-in-web-api.
Related
Need some help making my controllers DRY using the ASP.NET core
So, basically, I have an issue keeping my controllers non-fat and DRY.
Basically, let's say I have 4 controllers : controllerA, controllerB ... controllerD - the general structure of the code for each controller looks like this (pseudocode)
class controllerA
{
IActionResult Get(string ids)
{
//do validation on ids - if invalid return 404
// IEnumerable<obj> results= aservice.GetResource(ids)
-------------------------------------------------------------------------
//Logging of results
//logic which looks at results and determines whether to return a 404 or a 200
//return results
}
}
The logic after the dotted line is essentially repeated in 4 controllers - how can I make the controllers more DRY.
I have read about different solutions including using a DI service, a helper class, extension methods for the Controller type or an abstract class that these controllers can inherit from that extends the .NET controller class.
I am writing production code so would like to seek out a clean solution which is also best practice!
Thanks!
I would recommend to use MediatR nuget.
You can implement IPipelineBehavior<,> for each required step, in your example it will be:
Validation of ids
Logging
Your code will look like:
public async Task<IActionResult> Get(CustomCommand request)
{
var result = await _mediator.Send(request);
// return handled result
}
If you define command as parameter of action it will reduce code more, something like this
public async Task<IActionResult> Get(string ids)
{
// under the hood it will execute (depends on implementation):
// 1. validation of ids for the command
// 2. execute main logic which implemented in IRequestHandler<>
// 3. logging
// 4. return result
var result = await _mediator.Send(new CustomCommand(ids));
// return handled result
}
About results handling, there are two common ways functional programming or using exceptions.
Using exceptions
Create customer exceptions for your service, for example, NotFoundException, BadRequestException (better to call it something meaningful like ValidationException)
Throw them in cases where you need to stop execution and return unsuccessful result (for example, validation was failed)
Add global exception filter to asp.net which will handle this exceptions depends on it's type and it might use some custom data from it
Functional programming
Instead of simply returning response you will return Result object within the response, simple implemented of Result<T>:
public class Result<TValue>
{
public TValue Value { get; set; }
public bool IsSuccess { get; set; }
// you can add also something like 'ErrorCode' to specify how to handle
// failed result, for instance if ErrorCode is 400 (it can be readable
// string as well) you will return BadRequest()
}
Finally you can define in base controller class method to execute the logic and handle results
//... inside your base controller
public async Task<ActionResult<TResponse>> ExecuteAsync<TResponse>(IRequest<Result<TResponse>> request)
{
Result<TResponse> result = await Mediator.Send(request);
if(result.IsSuccess) return Ok(result.Value);
return result.ErrorCode switch
{
"some_error_code" => Conflict(result.ErrorMessage),
"other_code" => NotFound(),
_ => BadRequest(result.ErrorMessage)
};
}
//...
so the action code will be:
public Task<IActionResult> Get(CustomCommand request) => ExecuteAsync(request);
I want to write Unit test cases for following code
HomeController.cs
[HttpPost]
[ActionName("CreateDemo")]
public async Task<IHttpActionResult> CreateDemo([FromBody] MyRequest request)
{
if (request == null)
{
return BadRequest("request can not be null");
}
if (request.MyID == Guid.Empty)
{
return BadRequest("MyID must be provided");
}
}
I tried like following which is not correct way i guess so
[TestMethod]
public async Task NullCheck()
{
try
{
var controller = new HomeController();
var resposne = await controller.CreateDemo(null);
Assert.AreEqual(); // not sure what to put here
}
catch (HttpResponseException ex) //catch is not hit
{
Assert.IsTrue(
ex.Message.Contains("request can not be null"));
}
}
Each unit test shall test one requirement or concern. Your method implements two requirements:
1) If request is null, return BadRequestErrorMessageResult object with predefined error message.
2) If request's MyID property is empty GUID, return BadRequestErrorMessageResult object with another predefined error message.
This means we should have two unit tests:
[Test]
public async Task CreateDemo_returns_BadRequestErrorMessageResult_when_request_is_null()
{
// Arrange
var controller = new HomeController();
// Act
var response = await controller.CreateDemo(null);
// Assert
Assert.IsInstanceOf<BadRequestErrorMessageResult>(response);
Assert.AreEqual("request can not be null", response.Message);
}
[Test]
public async Task CreateDemo_returns_BadRequestErrorMessageResult_when_request_ID_is_empty_GUID()
{
// Arrange
var controller = new HomeController();
var request = new MyRequest(Guid.Empty);
// Act
var response = await controller.CreateDemo(request);
// Assert
Assert.IsInstanceOf<BadRequestErrorMessageResult>(response);
Assert.AreEqual("MyID must be provided", response.Message);
}
You can go even further and split each of these tests into two where one would test that return object is of the expected type and another that validates that returned object state is as expected (e.g. Message string is as expected). This way you would have a single assert per test.
Side notes:
You tagged this question with nunit tag so I provided the code which uses that framework. In your example though, you use [TestMethod] attribute which comes from Microsoft unit testing framework. If you want to use that framework you'd have to make some changes e.g. replace Assert.IsInstanceOf with Assert.IsInstanceOfType.
I assumed that GUID is passed to MyRequest via its constructor which assigns it to MyID.
I am not coming from web world but I found that BadRequest method has an overload which returns BadRequestErrorMessageResult if string is passed as its argument.
In my project we have created action based method like below...which work as expected in our project.
public async Task MyMethod(Action<bool> SuccessAction, Action<Exception> ErrorAction)
{
try
{
SuccessAction(false);
}
catch (Exception ex)
{
ErrorAction(ex);
}
}
Now, for testing the above method below is how i have written the test method using NUnit.
[Test]
public async Task MyFirstTest()
{
var myClass = new MyClass();
await myClass.MyMethod(
Result =>
{
Assert.IsTrue(Result);//as all are aware that this will throw an exception.
},
Error =>
{
Assert.Fail();
});
}
Now, my question is when ever there is an exception occured at MyFirstTest then that exception get caught at the MyMethod.
I am not sure why this is happening.
Can any one please provide an solution to handle this.
Please let me know if more information is required or my question is not clear.
I'm implementing an oauth provider using DotNetOpenAuth CTP library. So I have created an mvc3 application, which has an OAuth Controller with 3 methods in it with the purpose of authorizing third party applications. The controller has an IOAuthService which encapsulates all the logic that the library must do to complete certain tasks, however, the service methods return DotNetOpenOAuth objects that have their constructors protected.
I would like to test the behavior of the methods within my OAuthController, for this, I'm trying to mock my service methods but I havent't been able to do this. I have to tell moq library what type of object I'm expecting the service method to return, and since I cannot access constructors of these objects, I'm not able to perform a test over my controller method.
The controller:
public class OAuthController : Controller
{
private readonly IOAuthService _oAuthService;
public OAuthController(IOAuthService oAuthService)
{
_oAuthService = oAuthService;
}
[Authorize, AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Authorize()
{
ClientApplication requestingClient;
var request = _oAuthService.ReadAuthorizationRequest();
if (request == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
var response = _oAuthService.RequestClientAuthorization(GetIdentity().Name, out requestingClient, request);
if (response != null)
{
return response.AsActionResult();
}
var model = new AuthorizeClientApplicationViewModel
{
ClientApplication = requestingClient.Name,
Scope = request.Scope,
AuthorizationRequest = request,
};
return View(model);
}
public virtual IIdentity GetIdentity()
{
return User.Identity;
}
}
I want to test that whenever a third party app has no authorization, a view will pop up to the user asking for his permission to authorize the app. Fot this i need to mock:
_oAuthService.RequestClientAuthorization
The setup of my test method will then look like :
var oAuthService = new Mock<IOAuthService>();
oAuthService.Setup(a => a.RequestClientAuthorization(userName, out client, pendingRequest)).Returns(new OutgoingWebResponse()); // DotNetOpenAuth doesn't allow me to do the **new OutgoingWebResponse**
PD: For this question I only wrote one of the controller methods, but there are 3, and they have similar scenarios.
One possibility is to write a wrapper (the same way ASP.NET MVC abstracts all the HTTP Context specific stuff):
public abstract class OutgoingWebResponseWrapperBase
{
protected OutgoingWebResponseWrapperBase() { }
public abstract ActionResult AsActionResult();
}
and then have a naïve implementation:
public class OutgoingWebResponseWrapper: OutgoingWebResponseWrapperBase
{
private readonly OutgoingWebResponse _response;
public OutgoingWebResponseWrapper(OutgoingWebResponse response)
{
_response = response;
}
public override ActionResult AsActionResult()
{
return _response.AsActionResult();
}
}
Now modify the IOAuthService.RequestClientAuthorization method to return a OutgoingWebResponseWrapperBase instead of OutgoingWebResponse.
Just like that:
public interface IOAuthService
{
...
OutgoingWebResponseWrapperBase RequestClientAuthorization(...);
}
Obviously your controller code will stay absolutely the same. It's just that now you can mock the return type of the RequestClientAuthorization in your unit test because it is an abstract class. You can also mock the AsActionResult abstract method call to return some expected mocked instance and you will assert in your unit test that the controller action that you are testing returned this expected action result.
If the constructor is protected, then a derived type could access it. Can you simply use Moq to create a mock of OutgoingWebResponse (which internally will make Moq derive from it and call the protected constructor I think) and return that from your mock method implementation?
Something like this:
System.Net.HttpWebResponse mockResponse; // get this from somewhere
new Moq.Mock<DotNetOpenAuth.Messaging.OutgoingWebResponse>(mockResponse, 5);
This should let you mock up an OutgoingWebResponse. The next problem becomes, where do you get yoru HttpWebResponse instance, since that too has only a protected constructor. You could continue the chain and mock up that the same what as OutgoingWebResponse, and see how far you get.
What's the best way to unit test expected faults from WCF services?
I am attempting to unit test a WCF service which is (correctly) throwing FaultExceptions for a certain reproducible error. The unit tests get an instance of the WCF client and call the applicable service method, which throws a FaultException.
All of that works as you would expect, but I am having difficulty unit testing this, because the fault causes the IDE to break when the error isn't caught in the service implementation. Because I am using faults, and not exceptions, I was expecting the IDE to serialize the exception and send it to the client, where it would raise an exception.
I do see that there is a configuration option to disable breaking for specific user-unhandled exceptions, but I was hoping somebody could point out a better way to achieve the same results, as this isn't easily doable in a team environment.
Here's some sample code of what the implementation currently looks like...
The unit test project has a service reference to my WCF service, and I have defined the interface as such:
[OperationContract(Name = "DoSomething")]
[FaultContract(typeof(EpicFail))]
ResponseObject DoSomething(RequestObject requestObject);
The fault is defined as such:
[DataContract]
public class EpicFail
{
public EpicFail(string action)
{
this.Reason = "Epic Fail";
this.Action = action;
}
[DataMember]
public string Reason
{
get;
set;
}
[DataMember]
public string Action
{
get;
set;
}
}
The code that calls the service looks vaguely like this:
[TestMethod()]
[ExpectedException(typeof(FaultException<EpicFail>))]
public void FaultTest_Fails_Epicly()
{
bool testPassed = false;
try
{
ResponseObject resp = GetServiceClient().DoSomething(req);
}
catch (FaultException<EpicFail>)
{
testPassed = true;
}
Assert.IsTrue(testPassed);
}
I edited the code to show that I am using the ExpectedException attribute and it doesn't seem to be having much effect on keeping the IDE/Debugger from breaking when the exception is thrown in the service.
You can always use ExpectedExceptionAttribute (in NUnit) to make sure this is the exception thrown. MSTest has similar concept as well.
[ExpectedException(typeof(MyException))]
void my_test()
{
// test
}
If you have some Mock verification to do, I would use try/catch block and verify in the catch and then throw the exception.
UPDATE
When you are using ExpectedException attribute, you are not supposed to catch the exception, instead you need to let the NUnit that runs your test to catch it.
If you need to verify special information in the exception then you catch the exception, verify the information and then rethrow:
[ExpectedException(typeof(MyException))]
void my_test()
{
try
{
// call the service
}
catch(MyException ex)
{
Assert.IsTrue(ex.Message.Contains("error code 200"));
throw ex;
}
}
mattv,
Why does this test has to access the service remotely? From what I see your code:
ResponseObject resp = GetServiceClient().DoSomething(req);
Is somehow getting a service client, and not a service instance itself. I'd advise to test the service concrete class directly for unit tests.
However, if you need this scenario, have you tried NOT CATCHING the exception and running the test? Does it give the same result?
And by the way, if you need to catch and rethrow use the following pattern:
try {
//Do something
}
catch(SomeException e) {
//Do something with e
throw
}