10

When writing unit tests using Moq anytime I call the Elmah.ErrorSignal.FromCurrentContext it fails with a null reference exception. I am able to mock the ControllerContext and I would like to just use an error log command like this..

Elmah.ErrorSignal.FromContext(ControllerContext.HttpContext).Raise(e);

but unfortunately the ControllerContext.HttpContext is of type HttpContextBase and won't work with this error logging method.

Is there a better way to call the Elmah error logging directly? Unfortunately the Application.HttpContext object cannot be mocked (below example) or that would also serve the purpose.

Mock Application and Application.HttpContext:

ctrlCtx.SetupGet(x => x.HttpContext.ApplicationInstance)
           .Returns(new Mock<HttpApplication>().Object);
ctrlCtx.SetupGet(x => x.HttpContext.ApplicationInstance.Context)
           .Returns(new Mock<HttpContext>().Object);

Error Produced:

Invalid setup on a non-virtual (overridable in VB) member

nemesv
  • 138,284
  • 16
  • 416
  • 359
likestoski
  • 1,901
  • 4
  • 24
  • 41
  • related: [How can I mock Elmah's ErrorSignal routine?](http://stackoverflow.com/questions/1019833/how-can-i-mock-elmahs-errorsignal-routine) –  Dec 17 '14 at 10:14

2 Answers2

14

Though you can't mock HttpContext, you can set up HttpContext.Current in your test.

var req = new HttpRequest(string.Empty, "https://www.domain.tld", null);
var res = new HttpResponse(null);
HttpContext.Current = new HttpContext(req, res);

I'm not sure what parts of the context are used by Elmah though.

3rd party edit:
ELMAH also requires System.Web.HttpContext.Current.ApplicationInstance

Dim req As System.Web.HttpRequest = New System.Web.HttpRequest(String.Empty, "https://www.domain.tld", Nothing)
Dim res As System.Web.HttpResponse = New System.Web.HttpResponse(Nothing)
System.Web.HttpContext.Current = New System.Web.HttpContext(req, res)

System.Web.HttpContext.Current.ApplicationInstance = New System.Web.HttpApplication()

otherwise it throws an exception because application name is NULL.

Further edit:
Here is the final code in C#:

var req = new HttpRequest(string.Empty, "https://www.domain.tld", null);
var res = new HttpResponse(null);
HttpContext.Current = new HttpContext(req, res) 
     {ApplicationInstance = new HttpApplication()};
Geoff
  • 5,283
  • 2
  • 17
  • 11
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • Note that this worked for me on the first test run. But on re-runs I was getting exceptions again. I saw that vstest.console.exe was running in task manager. Killing this process allowed me to run the test again without Elmah exceptions – nf313743 Jan 31 '20 at 16:55
7

One thing you can do to log the error differently in Elmah is to use:

Elmah.ErrorLog.GetDefault(null).Log(new Elmah.Error(e)); 

Although this will not log an error from the unit test it will at least skip the logging altogether in the unit test and still log the error in normal circumstances.

Taterhead
  • 5,763
  • 4
  • 31
  • 40
likestoski
  • 1,901
  • 4
  • 24
  • 41