How to write Unit test for Action that throw HttpException with StatusCode 404 - asp.net-mvc-4

I have a below action in a controller which throw HttpException with status code 404:
public async Task<ActionResult> Edit(int id)
{
Project proj = await _service.GetProjectById(id);
if( proj == null)
{
throw new HttpException(404, "Project not found.");
}
}
To test this scenario, I have written below test case where I am catching AggregationException and rethrowing InnerException which is expected as HttpException:
[TestMethod]
[ExpectedException(typeof(HttpException),"Project not found.")]
public void Edit_Project_Load_InCorrect_Value()
{
Task<ActionResult> task = _projectController.Edit(3);
try
{
ViewResult result = task.Result as ViewResult;
Assert.AreEqual("NotFound", result.ViewName, "Incorrect Page title");
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
This test run succefully and return ExpectedException. I have two questions here:
Is this right approach for writing unit test or there is more
gracious way of testing it.
Is this possible to check in Unit Test
that user is getting correct error page( NotFound in this case).

There is a nicer way to test this. We wrote a class called AssertHelpers.cs that has this method in it. The reason this is nicer than ExpectedException is that ExpectedException does not actually verify it was thrown, it just allows the test to pass when it is thrown.
For example, if you change your 404 code to return 200 your test will not fail.
public static void RaisesException<TException>(Action dataFunction, string exceptionIdentifier = null)
{
bool threwException = false;
try
{
dataFunction();
}
catch (Exception e)
{
threwException = true;
Assert.IsInstanceOfType(e, typeof(TException));
if (exceptionIdentifier != null)
Assert.AreEqual(exceptionIdentifier, e.Message);
}
if (!threwException)
Assert.Fail("Expected action to raise exception with message: " + exceptionIdentifier);
}

Related

Clear API errors [UWP]

I have a problem with my API, the GET, POST, DELETE and PUT work perfectly. but if for some reason at the time of making a PUT or a POST I generate errors (404, 400, 500, etc) and it is normal that in some times for any query I generate errors ... the problem is that the next Once I go back to do a POST or PUT (being aware that it is ok) the error is stored and it does not let me make the new query ... I do not know what to do or what is wrong. but the GET is still working
THIS IS THE CONTROLLER CODE:
[HttpGet("{id}")] //GET
public async Task<IActionResult> Get(long id)
{
if (id == 0)
return BadRequest();
var tercero = await repository.GetAsync(id);
if (tercero == null)
return NotFound();
else
return Ok(tercero);
}
[HttpPost] //POST
public async Task<IActionResult> Post([FromBody]Tercero tercero)
{
try
{
return Ok(await repository.InsertAsync(tercero));
}
catch(Exception e)
{
return BadRequest(e.ToString());
}
}
[HttpPut("{id}")] //PUT
public async Task<IActionResult> Put([FromBody]Tercero tercero, long Id)
{
if (tercero.Id != Id)
return BadRequest("No hay correlacion entre el id y el objeto");
try
{
return Ok(await repository.UpdateAsync(tercero, Id));
}
catch (Exception e)
{
return BadRequest(e.ToString());
}
}
[HttpDelete("{id}")] //DELETE
public async Task<IActionResult> Delete(long id)
{
try
{
await repository.DeleteAsync(id);
return Ok();
}
catch (Exception e)
{
return BadRequest(e.ToString());
}
}
I have other controllers and with all the same thing happens. I do not know if he finds something to clean up the error
THIS IS WHAT HAPPENS
STEP 1:
I do a POST with a new User
It returns the model of the query with a 200 OK
STEP 2:
I generate an error giving the same code in one of the fields what the database does not allow me.
It shows me the error with a 400 Bad Request
STEP 3: I realize my mistake and I decide to correct it to make a correct POST
It gives me the same error
WHY? How can i fix it?

How to skip execution of test case from the Hooks in cucumber

I have to skip execution of the test case #bannerVerificationSMMDView only when the viewPort is Large
#Before
public void beforestartUp(Scenario scenario) throws IOException {
boolean runTest = true;
if (viewPort.contains("LARGE")) {
System.out.println("for Scenario " + scenario.getName() + " tagname are");
List<String> tags = (List<String>) scenario.getSourceTagNames();
for (String tagName : tags) {
if (tagName.contains("bannerVerificationLView"))
runTest = false;
}
try {
Assume.assumeTrue(runTest);
} catch (AssumptionViolatedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Not sure why, but exception is not getting caught
Throw a AssumptionViolatedException to skip the execution of scenario.
#Before(value="#bannerVerificationSMMDView")
public void before(Scenario scenario) {
if(viewPort.contains("LARGE"))
throw new AssumptionViolatedException("Skipping as view is LARGE");
}
If you are on cucumber version 3 plus, you can use a #BeforeStep annotation instead, keep everything else same. This will allow you to run any previous steps in the scenario and if condition is not met then skip the rest of the steps in the scenario

How do I log EntityValidation errors using ELMAH MVC?

I've been writing an application using MVC4 and EF5.x, and using ELMAH for logging exceptions for review. We recently released the application, and as expected the ELMAH log filled up with several dozen exceptions. Great (and not)! The problem is that one of those exceptions is
System.Data.Entity.Validation.DbEntityValidationException
Validation failed for one or more entities.
See 'EntityValidationErrors' property for more details.
Of course, there's no way to see the EntityValidationErrors property for more details and the stack trace wraps up to my SubmitChanges()
I know ELMAH has the capability of allowing us to raise our own exceptions, and in some way customize what gets logged and how. Unfortunately, I'm still very new to ELMAH and MVC and a Google search didn't turn up anything relevant. I did find a blog article on logging EntityValidationErrors, and the author specifically mentioned that he would post how to do so in ELMAH but that was posted in September of 2012 and I didn't see anything since then.
Any help would be greatly appreciated!
Probably the best thing to do in this case would be to wrap your context.SaveChanges(); call in a try...catch block and then log the individual items from the ValidationExceptions. Something like the following should get you started:
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ve)
{
var error = ve.EntityValidationErrors.First().ValidationErrors.First();
var msg = String.Format("Validation Error :: {0} - {1}",
error.PropertyName, error.ErrorMessage);
var elmahException = new Exception(msg);
Elmah.ErrorSignal.FromCurrentContext().Raise(elmahException);
}
How about this extension method based on the above..
public static void SaveChangesWithBetterValidityException(this DbContext context)
{
try
{
context.SaveChanges();
}
catch (DbEntityValidationException ve)
{
var errors = new List<string>();
foreach (var e in ve.EntityValidationErrors)
{
errors.AddRange(e.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, ve);
throw betterException;
}
}
Elmah will then have a much better exception in it's log
I added the following to my Global.asax.cs in order to forward all DbEntityValidationException exceptions to Elmah across my MVC application:
private void ElmahEntityValidationException()
{
var dbEntityValidationException = Server.GetLastError() as DbEntityValidationException;
if (dbEntityValidationException != null)
{
var errors = new List<string>();
foreach (var entityError in dbEntityValidationException.EntityValidationErrors)
{
errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, dbEntityValidationException);
Elmah.ErrorSignal.FromCurrentContext().Raise(betterException);
}
}
protected void Application_Error(object sender, EventArgs e)
{
ElmahEntityValidationException();
}
Some of this code was reused from #Paige Cook's and #Original10's posts.
Re-throwing as per the code below is not perfect (although I don't mind resetting the call stack here, as Elmah's logged details of the address posted to will show me what lead to the exception) and you will have to work out your own security implications, but this is fairly concise & meets my needs:
try
{
return base.SaveChanges();
}
catch (DbEntityValidationException e)
{
var de = new DetailedEntityValidationException(e);
throw de;
}
public class DetailedEntityValidationException : Exception
{
public DetailedEntityValidationException(DbEntityValidationException ve)
: base(ve.Message + ":\r\n\t-" + string.Join(new string('-',20) + "\r\n\t-", ve.EntityValidationErrors.Select(ev=>string.Join("\r\n\t-",ev.ValidationErrors.Select(e=>e.ErrorMessage)))))
{}
}
Here is my implementation for Global Web API solution for Elmah and EF Validation errors:
public class ElmahHandleWebApiErrorAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var e = context.Exception;
// Try parse as entity error (i'm not sure of performance implications here)
var efValidationError = e as DbEntityValidationException;
if (efValidationError == null)
{
RaiseErrorSignal(e);
}
else
{
RaiseEntityFrameWorkValidationErrorSignal(efValidationError);
}
}
private static bool RaiseErrorSignal(Exception e)
{
var context = HttpContext.Current;
if (context == null)
return false;
var signal = ErrorSignal.FromContext(context);
if (signal == null)
return false;
signal.Raise(e, context);
return true;
}
private static bool RaiseEntityFrameWorkValidationErrorSignal(DbEntityValidationException e)
{
var context = HttpContext.Current;
if (context == null)
return false;
var signal = ErrorSignal.FromContext(context);
if (signal == null)
return false;
//Taken from post above
var errors = new List<string>();
foreach (var entityError in e.EntityValidationErrors)
{
errors.AddRange(entityError.ValidationErrors.Select(e2 => string.Join("Validation Error :: ", e2.PropertyName, " : ", e2.ErrorMessage)));
}
var error = string.Join("\r\n", errors);
var betterException = new Exception(error, e);
signal.Raise(betterException, context);
return true;
}
}
and then I register the attribute in the WebApiConfig.cs file under App_Start
config.Filters.Add(new ElmahHandleWebApiErrorAttribute());

Issue : SQL Azure connection is broken . After reconnecting and accessing entity object , An Error occurred

Connected to website and keeping idle for 30 mins, then trying to access the entities I am getting the following error.
Entity framework An error occurred while executing the command definition. See the inner exception for details . Inner exception {“Invalid object name 'dbo.TableName'.”}
Sample Code
Static Class Azure
{
public static CrmEntities ConnectCustomerEntity()
{
CrmEntities customerEntity = null;
policy.ExecuteAction(() =>
{
try
{
var shardId = GetShardId();
customerEntity = new CrmEntities(ConnectionStringCustomerDB());
string federationCmdText = #"USE FEDERATION Customer_Federation(ShardId =" + shardId + ") WITH RESET, FILTERING=ON";
customerEntity.Connection.Open();
customerEntity.ExecuteStoreCommand(federationCmdText);
}
catch (Exception e)
{
customerEntity.Connection.Close();
SqlConnection.ClearAllPools();
//throw e;
}
});
return customerEntity;
}
public static CrmEntities DBConnect(CrmEntities _db)
{
try{
if (_db == null)
_db = Azure.ConnectCustomerEntity();
if ((_db.Connection.State == ConnectionState.Broken) || (_db.Connection.State == ConnectionState.Closed))
{
SqlConnection.ClearAllPools();
_db = Azure.ConnectCustomerEntity();
}
else
{ //This code is to find out any issues in connection pool database connection
string sqlCmdText = #"select top 1 Id from Project";
_db.ExecuteStoreCommand(sqlCmdText);
}
}
catch (Exception ex)
{
_db.Connection.Close();
SqlConnection.ClearAllPools();
_db = Azure.ConnectCustomerEntity();
}
return _db;
}
}
Mvc Controller. The following code I am gettting that exception, after 30 mins
public class FilterController : Controller
{
public ActionResult GetFilters(string entityName,string typeFilter)
{
_crmEntities=Azure.DBConnect(_db);
var query = _db.FilterFields.Where(filter => filter.TableId == tableId).ToList(); // Here I am getting that exception
}
}
I dont know, Why i m getting that exception. I tried all possibilities. Nothing helped. I really struck with this. If anybody knows please tell your views to come out from this exception
Thanks in Advance.
I think your session times out.
try to increase session timeout:
http://msdn.microsoft.com/en-us/library/system.web.sessionstate.httpsessionstate.timeout.aspx

How do I force a method in Groovy to throw an exception

I wanted to write a test for a method in Groovy that throws an IOException. The only way for me to simulate this in the test is to force the method to throw this exception
This is what the original code looks like:
public void cleanUpBermudaFiles(RequestMessage requestMessage)
{
final File sourceDirectory = new File(preferenceService.getPreference("bermuda.landingstrip") + File.separator + requestMessage.getWorkflowId().getValue());
if(sourceDirectory!=null && sourceDirectory.exists())
{
deleteDirectory(sourceDirectory);
}
else
{
LOG.error("Directory must exist in order to delete");
}
}
private void deleteDirectory(File directoryToDelete)
{
try {
FileUtils.deleteDirectory(directoryToDelete);
} catch (Exception e) {
LOG.error("Failed to delete Bermuda files directory located at:" + directoryToDelete.getPath() + "with an exception" + e.getMessage());
}
}
MY TEST: (I'm looking for a way to make deleteDirectory throw IOException)
public void testCleanUpBermudaFailure()
{
workflowId = new WorkflowId("123456")
workflowDirectory = new File(srcDirectory, workflowId.value)
workflowDirectory.mkdir()
File.createTempFile('foo','.lst', workflowDirectory)
def exception = {throw new IOException()}
expect(mockRequestMessage.getWorkflowId()).andReturn(workflowId)
expect(mockPreferenceService.getPreference("bermuda.landingstrip")).andReturn(srcDirectory.path)
replay(mockPreferenceService, mockRequestMessage)
fileCleanUpService.preferenceService = mockPreferenceService
fileCleanUpService.metaClass.deleteDirectory = exception
fileCleanUpService.cleanUpBermudaFiles(mockRequestMessage)
verify(mockPreferenceService, mockRequestMessage)
assert srcDirectory.listFiles().length == 0, 'CleanUp failed'
}
If the service class is a Groovy class, you would want to mock FileUtils like:
FileUtils.metaClass.static.deleteDirectory = { File f -> throw new IOException() }
However, as ataylor pointed out, you cannot intercept calls if it's a Java class. You can find a nice blog post about it here.
You are mocking a no-arg call to deleteDirectory, but the real deleteDirectory takes one argument of type File. Try this:
def exception = { File directoryToDelete -> throw new IOException() }
...
fileCleanUpService.metaClass.deleteDirectory = exception