I want to write unit tests for a web service. I create my test project, reference my web project (not service reference, assembly reference), then write some code to test the web services - they work fine. However, there are some services which make sure the user is logged in to the web application by using HttpContext.Current.User.Identity.IsAuthenticated
.
In the context of the tests, there is no such thing as HttpContext, so the tests always fail. How should these kinds of web services be unit tested?
The HttpContext encapsulates all the HTTP-specific information about a single HTTP request. When an HTTP request arrives at the server, the server processes the request and builds an HttpContext object. This object represents the request which your application code can use to create the response.
HttpContextBase was added later to address HttpContext being difficult to mock. The two classes are basically unrelated ( HttpContextWrapper is used as an adapter between them). Fortunately, HttpContext itself is fakeable just enough for you do replace the IPrincipal (User) and IIdentity .
Unit testing involves testing a part of an application in isolation from its infrastructure and dependencies. When you unit test controller logic, only the content of a single action or method is tested, not the behavior of its dependencies or of the framework itself.
Here is a related discussion.
I stopped referencing HttpContext.Current
directly. and use this class instead:
public class HttpContextFactory
{
private static HttpContextBase m_context;
public static HttpContextBase Current
{
get
{
if (m_context != null)
return m_context;
if (HttpContext.Current == null)
throw new InvalidOperationException("HttpContext not available");
return new HttpContextWrapper(HttpContext.Current);
}
}
public static void SetCurrentContext(HttpContextBase context)
{
m_context = context;
}
}
and use HttpContextFactory.Current
instead of HttpContext.Current
in our code.
Then you write this in your test:
HttpContextFactory.SetCurrentContext(GetMockedHttpContext());
where GetMockedHttpContext() is from here and looks like this:
private System.Web.HttpContextBase GetMockedHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var user = new Mock<IPrincipal>();
var identity = new Mock<IIdentity>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
context.Setup(ctx => ctx.User).Returns(user.Object);
user.Setup(x => x.Identity).Returns(identity.Object);
identity.Setup(id => id.IsAuthenticated).Returns(true);
identity.Setup(id => id.Name).Returns("test");
return context.Object;
}
It uses a mocking framework called moq
In your test project you have to add a reference to System.Web
and System.Web.Abstractions
, where HttpContextBase
is defined.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With