Unit Testing Webform HttpContext Dependent code? - c#

Im trying to write some unit tests for a couple of merthods that are dependant on the HttpContext object. I have come up with the following class but I dont think its the best way to do it.
internal class HttpContextMocking
{
public static HttpContext Context()
{
HttpContext context = new HttpContext(new SimpleWorkerRequest("", "", "", null, new StringWriter()));
context.Cache.Insert("SomeName", "value", null, DateTime.Now.AddMinutes(3), TimeSpan.Zero);
return context;
}
I then call this mock HttpContext in my unit test in the following way:
[TestMethod]
[TestCategory("Web")]
public void Get()
{
HttpContext.Current = HttpContextMocking.Context();
object result = CacheUtility.Get("NonExistentItem");
Assert.IsNull(result);
}
is there a better way of implementing this, something that would be cleaner when I start to add more dummy data.

HttpContext is really complex to mock. I will suggest to change the dependency to an interface that provides what you need, and then have two implementations: a real one, using HttpContext and a Mock one for the tests.
If you anyway want to mock it and your code does the trick, leave it that way.
Another option is to use the ASP.NET host type for MSTest. In this case, you will be performing an actual request and your HttpContext will be there:
[TestMethod]
[HostType("ASP.NET")]
[AspNetDevelopmentServerHost(#"$(SolutionDir)\Tests", "/")]
[UrlToTest("http://localhost:1234/TestPage.aspx")]
public void MyTest()
{
Page page = testContextInstance.RequestedPage;
...
}

The HttpContextWrapper and HttpContextBase .NET classes were created for mocking purposes e.g. http://www.codemerlin.com/2011/07/mocking-httpcontext-httpresponse-httprequest-httpsessionstate-etc-in-asp-net/

Related

.NET Core container definition for NUnit test project

I am quite new to .NET Core. How can I define a DI container within the NUnit class library project?
I know that it is done through IServiceCollection, but since there isn't any Startup method, I don't know where to get the instance implementing this interface.
Also I would like to be able to load definitions from other class libraries (being the subject of testing). That should be simpler as I can just create a static method in that class library with one parameter that is IServiceCollection, but again, how do I get it?
A side question is: I presume some of the interfaces could be mocked for the purpose of tests, but how can I replace a mapping already created using of of IServiceCollection's methods like AddSingleton or AddTransient?
There is a Remove method, but it is not documented.
IServiceCollection is implemented by the ServiceCollecion class. So if you want to do this for integration tests then you can use the ServiceCollection class to create your own ServiceProvider.
var services = new ServiceCollection();
services.AddTransient<IMyInterface, MyClass>();
services.AddScoped<IMyScopedInteface, MyScopedClass>();
...
var serviceProvider = sc.BuildServiceProvider();
You can now use the serviceProvider instance in your tests to get your classes:
var myClass = serviceProvider.GetService<IMyInterface>();
If you want to mock some of the interfaces instead of using the real ones then, instead of adding the real class/interface into the service collection you can add a mock instead:
mockInterface = new Mock<IMyInterface>();
sc.AddScoped<IMyInterface>(factory => mockInterface.Object);
Generally you don't want to create a DI container for your tests but, as you realise, you want to mock them instead. So, for example, if this is a class you want to test:
public class UserService
{
private readonly IUserDatabase _userDatabase;
public UserService(IUserDatabase userDatabase)
{
_userDatabase = userDatabase;
}
public bool DoesUserExist(int userId)
{
return _userDatabase.UserExists(userId);
}
}
And this is the definition of the interface used:
public interface IUserDatabase
{
bool UserExists(int userId);
}
In our tests we can mock the interface to return a specific value we want for our test:
[TestClass]
public class UserServiceTests
{
[TestMethod]
public void DoesUserExist_ForValidUserId_ReturnsTrue()
{
var fakeUserId = 123;
var mockUserDatabase = new Mock<IUserDatabase>();
mockUserDatabase.Setup(udb => udb.UserExists(fakeUserId)).Returns(true);
var userService = new UserService(mockUserDatabase.Object);
var result = userService.DoesUserExist(fakeUserId);
Assert.IsTrue(result);
mockUserDatabase.VerifyAll();
}
}
So in this test we have used Moq to create a mock of our interface. We don't need to use a DI container because we are in controller of creating the class we are testing. The DI container is of more use in production as it enables the application to create any dependencies it needs without your code having to call new - which is a big problem if you are trying to unit test your classes.
The .VerifyAll() method checks that any methods set up on the mock object, in this case we setup a call to UserExists, was actually called.
There are plenty of examples of how to use Moq and mocking interfaces in general. A quickstart guide to Moq is here.

Mock HttpContext.Current.User.Identity.Name

I'm currently writing unit test for my project where I'm using HttpContext.Current.User.Identity.Name at a defined time. Unfortunately, I can't make the test work since HttpContext is null when I run the test.
I already tried some solution I found on internet like Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("rmllcc"), new string[0]); but I can't get it work.
I'm using a Forms Authenticate system, xUnit with Moq. I'm not testing a controller but a Repository where I'm just logguing each time a user make use of a particular method. How could I accomplish this?
Listen to what your tests are telling you: use the fact that this test is hard to write to think about the structure of your code. You have introduced a dependency in your repository layer to the web application. That's not good. You also have two things going on in your repository: data access and logging.
Maybe wrap the current user in an abstraction that will get the user you need, but can be easily stubbed. Or you could wrap the repository in a decorator that does the logging for you.
Sorry this is not a direct answer to the question but, when tests are hard to write, there is usually a deeper underlying reason that you need to address.
I suggest you dont use the HttpContext from the repository, Make a own context class or a Interface wrapping the user-property.
Something like this:
public class MyContext
{
public MyContext(string username)
{
Username = username;
}
public string Username { get; private set; }
public static MyContext CreateFromHttpContext(HttpContext httpContext){
return new MyContext(HttpContext.Current.User.Identity.Name);
}
}
public class MyRep
{
private readonly VtContext _context;
public MyRep(MyContext context)
{
_context = context;
}
... other repository code...
}
then just create a MyContext in your test:
var rep = new MyRep(new MyContext("unittest"));

NullReferenceException in unit test result

I've just started programming in C# Webforms (previous experience in VB Webforms) and I am producing a web app that will be a small part of a bigger project.
I have created 3 separate projects, one for the webforms, one for the class library and one for the tests.
I have added all the projects into one solution and added appropriate references, Both the Webforms and Tests projects reference the class library.
I have a class in the class library that finds the username of the logged in user:
public class LoggedInUser
{
public string UserName
{
get { return HttpContext.Current.User.Identity.Name; }
}
}
In the page load event of one of my pages, I use this class to set the text property of a literal to display the name on the screen.
protected void Page_Load(object sender, EventArgs e)
{
LoggedInUser CurrentUser = new LoggedInUser();
LitUser.Text = string.Format(" {0}", CurrentUser.UserName);
}
This works fine.
To be complete I thought I would write a unit test to make sure the logged in username is what I expected.
[TestMethod]
public void Test_Logged_In_User_Name()
{
LoggedInUser actualUser = new LoggedInUser();
string expectedUserName = "myUserName";
string actualUserName = actualUser.UserName;
Assert.AreEqual(expectedUserName, actualUserName);
}
When I run the test it throws the following exception:
System.NullReferenceException: Object reference not set to an instance of an object
on this line:
get { return HttpContext.Current.User.Identity.Name; }
Any thoughts would as always be greatly appreciated.
You'll need to create a wrapper class for HttpContext that abstracts the functionality you need. The reason for this is that HttpContext only exists for web requests and as you are running your unit tests from an application HttpContext will not exist.
Additionally any 3rd party dependency should have a wrapper created for it to assist with testing.
It's worth noting, you also shouldn't need this test at all. In this instance you are testing a 3rd parties code, something you are relying on to be accurate. The purpose of unit tests is to test your own code/logic and if you wrote tests for every 3rd party method you'd never get a product released :).
As for creating a wrapper class, they are not dissimilar from ordinary classes. You'd need to create an interface for the HttpContext class and then create a wrapper something like the below:
public class HttpContextWrapper
{
private readonly IHttpContext _httpContext;
public HttpContextWrapper()
{
_httpContext = HttpContext.Current;
}
public HttpContextWrapper(IHttpContext injectedContext)
{
_httpContext = injectedContext;
}
public string GetName()
{
_httpContext.Current.User.Identity.Name;
}
}
You could then inject a fake implimentation of HttpContext to get your desired results.
Actually, you don't necessarily need to wrap and mock the HttpContext. In your test setup, you can do something similar to the following:
var sb = new StringBuilder();
TextWriter writer = new StringWriter(sb);
HttpContext.Current = new HttpContext(
new HttpRequest("path", "http://dummy", ""),
new HttpResponse(writer)
)
{
User = new WindowsPrincipal(WindowsIdentity.GetCurrent())
};
In this example, I assign a windows principal with the identity of the current user, but in your scenario you may want to assign a specifically crafted principal, e.g. a ClaimsPrincipal or a fake implementation (or a mock).

How to mock or fake HttpApplication / HttpContext for testing

I'm trying to run some tests on my MVC application but I've been experiencing a world of trouble getting it to work. I'll try to get right to the point:
I'm using RhinoMocks to try something like this:
Setup:
MockRepository mocks = new MockRepository();
HttpContextBase _mockContext = mocks.FakeHttpContext();
mocks.SetFakeControllerContext(new LoginController());
HttpApplicationStateBase appState = MockRepository.GenerateStub<HttpApplicationStateBase>();
_mockContext.Expect(mc => mc.Application).Return(appState);
HttpContext.Current = _mockContext.ApplicationInstance.Context;
Here's the FakeHttpContext() method:
public static HttpContextBase FakeHttpContext(this MockRepository mocks)
{
HttpApplication app = mocks.PartialMock<HttpApplication>();
HttpContextBase context = mocks.PartialMock<HttpContextBase>();
HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
HttpResponseBase response = mocks.PartialMock<HttpResponseBase>();
HttpSessionStateBase session = mocks.PartialMock<HttpSessionStateBase>();
HttpServerUtilityBase server = mocks.PartialMock<HttpServerUtilityBase>();
SetupResult.For(context.ApplicationInstance).Return(app);
SetupResult.For(context.Request).Return(request);
SetupResult.For(context.Response).Return(response);
SetupResult.For(context.Session).Return(session);
SetupResult.For(context.Server).Return(server);
mocks.Replay(context);
return context;
}
I really need to access HttpContextBase.Request.AppRelativeCurrentExecutionFilePath but it's always returned as null. The same goes for HttpContext.Current.Request.RequestContext.
Can anybody help me out here? It's safe to say I'm desperate at this point.
First of all, try avoid using HttpContext.Current as using a static method makes it much harder to test as you have found out now. If you are using a dependency injection framework, inject HttpContextBase into your constructor.
For your actual problem, in FakeHttpContext() try to change
HttpRequestBase request = mocks.PartialMock<HttpRequestBase>();
to
HttpRequestBase request = mocks.GenerateStub<HttpRequestBase>();
and then in your test you can do something like this:
_mockContext.Request.Stub(x=> x.AppRelativeCurrentExecutionFilePath).Return("foo");
var result = object.DoSomething();
Assert.AreEqual("foo",result);
I don't think it's quite useful to do partial mocking on the HttpContext as you will be testing the framework instead (i.e. test that the framework returns you the correct value X based on value Y and Z in the HttpContext)
Another alternative is to create a wrapper class around HttpContextBase that will return you computed values. E.g. HttpContextBaseWrapper.AppRelativeCurrentExecutionFilePath(), HttpContextBaseWrapper.RequestIpAddress(). This will make testing ALL your other classes less complicated as they do not have to worry about mocking HttpContextBase and the details, they simply have to mock your HttpContextBaseWrapper class.
Edit:
I'd also recommend you to inject your HttpRequestContext as well, but if that's not possible then you can stub the RequestContext like so in the FakeHttpContext method:
var requestContext = MockRepository.GenerateStub<RequestContext>();
request.RequestContext = requestContext;
Why don't you make an abstraction class which contains calls to the HttpContext base?
Then you can do something like this:
public class MyClass
{
private readonly IHttpContext _httpContext;
MyClass(IHttpContext httpContext)
{
_httpContext = httpContext;
}
public void Blaat()
{
_httpContext.DoYourThingsWithTheHttpContext();
}
}
Assuming you are using dependency injection, otherwise look at the Fakes and Stubs framework from Microsoft.

Moq: unit testing a method relying on HttpContext

Consider a method in a .NET assembly:
public static string GetSecurityContextUserName()
{
//extract the username from request
string sUser = HttpContext.Current.User.Identity.Name;
//everything after the domain
sUser = sUser.Substring(sUser.IndexOf("\\") + 1).ToLower();
return sUser;
}
I'd like to call this method from a unit test using the Moq framework. This assembly is part of a webforms solution. The unit test looks like this, but I am missing the Moq code.
//arrange
string ADAccount = "BUGSBUNNY";
string fullADName = "LOONEYTUNES\BUGSBUNNY";
//act
//need to mock up the HttpContext here somehow -- using Moq.
string foundUserName = MyIdentityBL.GetSecurityContextUserName();
//assert
Assert.AreEqual(foundUserName, ADAccount, true, "Should have been the same User Identity.");
Question:
How can I use Moq to arrange a fake HttpContext object with some value like 'MyDomain\MyUser'?
How do I associate that fake with my call into my static method at MyIdentityBL.GetSecurityContextUserName()?
Do you have any suggestions on how to improve this code/architecture?
Webforms is notoriously untestable for this exact reason - a lot of code can rely on static classes in the asp.net pipeline.
In order to test this with Moq, you need to refactor your GetSecurityContextUserName() method to use dependency injection with an HttpContextBase object.
HttpContextWrapper resides in System.Web.Abstractions, which ships with .Net 3.5. It is a wrapper for the HttpContext class, and extends HttpContextBase, and you can construct an HttpContextWrapper just like this:
var wrapper = new HttpContextWrapper(HttpContext.Current);
Even better, you can mock an HttpContextBase and set up your expectations on it using Moq. Including the logged in user, etc.
var mockContext = new Mock<HttpContextBase>();
With this in place, you can call GetSecurityContextUserName(mockContext.Object), and your application is much less coupled to the static WebForms HttpContext. If you're going to be doing a lot of tests that rely on a mocked context, I highly suggest taking a look at Scott Hanselman's MvcMockHelpers class, which has a version for use with Moq. It conveniently handles a lot of the setup necessary. And despite the name, you don't need to be doing it with MVC - I use it successfully with webforms apps when I can refactor them to use HttpContextBase.
In general for ASP.NET unit testing, rather than accessing HttpContext.Current you should have a property of type HttpContextBase whose value is set by dependency injection (such as in the answer provided by Womp).
However, for testing security related functions I would recommend using Thread.CurrentThread.Principal (instead of HttpContext.Current.User). Using Thread.CurrentThread has the advantage of also being reusable outside a web context (and works the same in a web context because the ASP.NET framework always sets both values the same).
To then test Thread.CurrentThread.Principal I usually use a scope class that sets the Thread.CurrentThread to a test value and then resets on dispose:
using (new UserResetScope("LOONEYTUNES\BUGSBUNNY")) {
// Put test here -- CurrentThread.Principal is reset when PrincipalScope is disposed
}
This fits well with the standard .NET security component -- where a component has a known interface (IPrincipal) and location (Thread.CurrentThread.Principal) -- and will work with any code that correctly uses/checks against Thread.CurrentThread.Principal.
A base scope class would be something like the following (adjust as necessary for things like adding roles):
class UserResetScope : IDisposable {
private IPrincipal originalUser;
public UserResetScope(string newUserName) {
originalUser = Thread.CurrentPrincipal;
var newUser = new GenericPrincipal(new GenericIdentity(newUserName), new string[0]);
Thread.CurrentPrincipal = newUser;
}
public IPrincipal OriginalUser { get { return this.originalUser; } }
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing) {
if (disposing) {
Thread.CurrentPrincipal = originalUser;
}
}
}
Another alternative is, instead of using the standard security component location, write your app to use injected security details, e.g. add an ISecurityContext property with a GetCurrentUser() method or similar, and then use that consistently throughout your application -- but if you are going to do this in the context of a web application then you might as well use the pre-built injected context, HttpContextBase.
[TestInitialize]
public void TestInit()
{
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
}
Also you can moq like below
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(p => p.HttpContext.Session["User"]).Returns(TestGetUser);
controllerContext.SetupGet(p => p.HttpContext.Request.Url).Returns(new Uri("http://web1.ml.loc"));
In ASP.NET MVC Core I use the following code to test controllers, which depend on HttpContext:
var controller = new HomeController();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
This is a sample unit test:
[Test]
public void Test_HomeController_Index()
{
// Arrange
var controller = new HomeController();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
// Act
var result = controller.Index();
// Assert
var viewResult = result as ViewResult;
Assert.IsNotNull(viewResult);
}
Have a look at this
http://haacked.com/archive/2007/06/19/unit-tests-web-code-without-a-web-server-using-httpsimulator.aspx
Using httpSimulator class,You will be able to do pass a HttpContext to handler
HttpSimulator sim = new HttpSimulator("/", #"C:\intepub\?")
.SimulateRequest(new Uri("http://localhost:54331/FileHandler.ashx?
ticket=" + myticket + "&fileName=" + path));
FileHandler fh = new FileHandler();
fh.ProcessRequest(HttpContext.Current);
HttpSimulator implement what we need to get a HttpContext instance. So you don't need to use Moq here.
If you're using the CLR security model (as we do) then you'll need to use some abstracted functions to get and set the current principal if you want to allow testing, and use these whenever getting or setting the principal. Doing this allows you to get/set the principal wherever is relevant (typically on HttpContext on the web, and on the current thread elsewhere like unit tests). This would look something like:
public static IPrincipal GetCurrentPrincipal()
{
return HttpContext.Current != null ?
HttpContext.Current.User :
Thread.CurrentThread.Principal;
}
public static void SetCurrentPrincipal(IPrincipal principal)
{
if (HttpContext.Current != null) HttpContext.Current.User = principal'
Thread.CurrentThread.Principal = principal;
}
If you use a custom principal then these can be fairly nicely integrated into its interface, for example below Current would call GetCurrentPrincipal and SetAsCurrent would call SetCurrentPrincipal.
public class MyCustomPrincipal : IPrincipal
{
public MyCustomPrincipal Current { get; }
public bool HasCurrent { get; }
public void SetAsCurrent();
}
This is not really related in using Moq for unit testing of what you need.
Generally we at work have a layered architecture, where the code on the presentation layer is really just for arranging things for being displayed on the UI. This kind of code is not covered with unit tests. All the rest of the logic resides on the business layer, which doesn't have to have any dependency on the presentation layer (i.e. UI specific references such as the HttpContext) since the UI may also be a WinForms application and not necessarily a web application.
In this way you can avoid to mess around with Mock frameworks, trying to simulate HttpRequests etc...although often it may still be necessary.

Categories

Resources