Mocking static method in ASP.NET MVC Test project - asp.net-mvc

I have a method which looks like the one below
public List<Rajnikanth> GetRajnis()
{
string username = Utility.Helpers.GetLoggedInUserName();
return _service.GetRajni(username);
}
Utility.Helper is a static class,
public static class Helpers
{
public static String GetLoggedInUserName()
{
string username = "";
if (System.Web.HttpContext.Current.User.Identity.IsAuthenticated)
{
username = ((System.Web.Security.FormsIdentity)HttpContext.Current.User.Identity).Ticket.Name;
}
return username;
}
}
I want to test : GetRajnis()
I want to mock : GetLoggedInUserName()
So my test method looks something like...
[TestMethod]
public void TestGetRajnis()
{
SomeController s = new SomeController(new SomeService());
var data = s.GetRajnis();
Assert.IsNotNull(data);
}
how do I mock the static method GetLoggedInUserName() ?

The Simplest Approach: Override the return value
If you are looking to mock a return value, then this is very simple. You can modify the Utility.Helper class to include a property called OverrideLoggedInUserName. When someone calls GetLogedInUserName(), if the override property is set, it is returned, otherwise the normal code to get the value from the HttpContext is used to get the return value.
public static class Helper
{
// Set this value to override the return value of GetLoggedInUserName().
public static string OverrideLoggedInUserName { get; set; };
public static string GetLoggedInUserName()
{
// Return mocked value if one is specified.
if ( !string.IsNullOrEmpty( OverrideLoggedInUserName ) )
return OverrideLoggedInUserName;
// Normal implementation.
string username = "";
if ( System.Web.HttpContext.Current.User.Identity.IsAuthenticated )
{
username = ( (System.Web.Security.FormsIdentity)HttpContext.Current.User.Identity ).Ticket.Name;
}
return username;
}
}
This will effectively allow you to override the return value, which technically isn't a mock--it's a stub (according to the excellent article Mocks Aren't Stubs by Martin Fowler). This allows you to stub a return value, but won't allow you to assert whether the method was called or not. Anyhow as long as you only want to manipulate the return value this works fine.
Here is how you would use this in a test.
[ TestMethod ]
public void TestGetRajnis()
{
// Set logged in user name to be "Bob".
Helper.OverrideLoggedInUserName = "Bob";
SomeController s = new SomeController( new SomeService() );
var data = s.GetRajnis();
// Any assertions...
}
This design does have one drawback. Because it's a static class, if you set the override value, it remains set until you un-set it. So you must remember to re-set it to null.
A Better Approach: Inject the dependency
A better approach may be to create a class that retrieves the logged in user name, and pass it into the constructor of SomeController. We call this dependency injection. This way, you can inject a mocked instance into it for testing, but pass the real instance (that gets the user from the HttpContext) when not testing. This is a much cleaner and clearer approach. Plus, you can leverage all the power of whatever mocking framework you are using, since they are designed specifically to handle this approach. Here is what that would look like.
// Define interface to get the logged in user name.
public interface ILoggedInUserInfo
{
string GetLoggedInUserName();
}
// Implementation that gets logged in user name from HttpContext.
// This class will be used in production code.
public class LoggedInUserInfo : ILoggedInUserInfo
{
public string GetLoggedInUserName()
{
// This is the same code you had in your example.
string username = "";
if ( System.Web.HttpContext.Current.User.Identity.IsAuthenticated )
{
username = ( (System.Web.Security.FormsIdentity)HttpContext.Current.User.Identity ).Ticket.Name;
}
return username;
}
}
// This controller uses the ILoggedInUserInfo interface
// to get the logged in user name.
public class SomeController
{
private SomeService _service;
private ILoggedInUserInfo _userInfo;
// Constructor allows you inject an object that tells it
// how to get the logged in user info.
public SomeController( SomeService service, ILoggedInUserInfo userInfo )
{
_service = service;
_userInfo = userInfo;
}
public List< Rajnikanth > GetRajnis()
{
// Use the injected object to get the logged in user name.
string username = _userInfo.GetLoggedInUserName();
return _service.GetRajni( username );
}
}
And here is a test using Rhino Mocks to inject a stub object into the controller.
[ TestMethod ]
public void TestGetRajnis()
{
// Create a stub that returns "Bob" as the current logged in user name.
// This code uses Rhino Mocks mocking framework...
var userInfo = MockRepository.GenerateStub< ILoggedInUserInfo >();
userInfo.Stub( x => x.GetLoggedInUserName() ).Return( "Bob" );
SomeController s = new SomeController( new SomeService(), userInfo );
var data = s.GetRajnis();
// Any assertions...
}
The disadvantage here is that you can't just call Helper.GetLoggedInUserName() from anywhere in your code, because it's no longer static. However, you no longer have the need to reset the stubbed username every time you finish a test. Because it's not static, it it automatically reset. You just recreate it for the next test and set a new return value.
I hope this helps.

Get rid of the static class if you are looking for testability. A simple fix for now would be to create a wrapper around the static class. Unless you use something like TypeMock or something equally as powerful, then you cannot alter the logic of a static class. Nor do I suggest it. If you have to stub a static class, it probably should not be a static class.
public class StaticWrapper
{
public virtual String GetLoggedInUserName()
{
Utility.Helpers.GetLoggedInUserName();
}
}

Related

Unit Testing a Controller - How Do I Handle the Connection String?

I can make it work, but I want to know what the best practice is and why. I have a Controller, a Model, and a Repository and now I want to Unit Test the Controller. I am just writing a simple test to ensure that the correct view is being returned.
This is my method in the controller:
public ActionResult Selections(SelectionsViewModel model)
{
for (int i = 0; i < model.Sends.Count; i++)
{
Send send = new Send(new SendService(new Database().GetConnectionString()))
{
SendID = model.Sends[i].SendID,
Title = model.Sends[i].Title,
Subject = model.Sends[i].Subject,
SentDate = model.Sends[i].SentDate,
TimesViewed = model.Sends[i].TimesViewed,
Include = model.Sends[i].Include,
Exclude = model.Sends[i].Exclude
};
send.UpdateIncludeExclude();
}
return View(model);
}
Here is my GetConnectionString() method in the Database class that is being sent via my SendService constructor.
public string GetConnectionString()
{
return System.Configuration.ConfigurationManager.ConnectionStrings["DEVConnectionString"].ToString();
}
And lastly, my unit test:
[Test]
public void TestAssignmentSelections()
{
var obj = new AssignmentController();
var actResult = obj.Selections() as ViewResult;
NUnit.Framework.Assert.That(actResult.ViewName, Is.EqualTo("Selections"));
}
Now, my unit test fails, and I get why. My unit test project has no access to the web.config of the project I am testing where my connection string resides.
I've done some research, and apparently just adding a web.config to my unit test project and putting the connection string in there as well will make it work.. but that seems like a hack.
What's the best way to go about this? Is there another way to write my code to accommodate for this?
You want to make your controller unit testable ? Don't do this.
new SendService(
With this code,you are hardcoding your concrete service implementation & your data access code implementation. In your unit test, you should not be really accessing the data from your database. Instead you should be providing a mock data access implementation.
Here comes interfaces, you need to create an interface for your SendService.
public interface ISendService
{
void SomeMethod();
}
now your SendService will be a concrete implementation of this interface
public class SendService : ISendService
{
public void SomeMethod()
{
// Do something
}
}
Now update your controller to have a constructor where we will inject an implementation of ISendService.
public class YourController : Controller
{
private ISendService sendService;
public YourController(ISendService sendService)
{
this.sendService = sendService;
}
public ActionResult YourActionMethod()
{
// use this.sendService.SomeMethod();
}
}
And you may use some dependency injection frameworks to tell the MVC framework which implementation of the interface to use when the code runs. If you are using MVC6,It has an inbuilt dependency injection provider you can use. So go to your Startup class and in your ConfigureServices method, you can map an interface to a concrete implementation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<ISendService, SendService>();
}
}
If you are in a previous version of MVC, You may consider DI frameworks like Unity,Ninject etc. You can do the same approach for your Data access later / Service layers. ie: Create an interface for data access and inject that to your SendService.
public Interface IDataAccess
{
string GetName(int id);
}
and an implementation which uses your specific data access code/ORM
public class EFDataAccess : IDataAccess
{
public string GetName(int id)
{
// return a string from db using EF
}
}
So now your Service class will be
public class SendService : ISendService
{
private IDataAccess dataAccess;
public SendService(IDataAccess dataAccess)
{
this.dataAccess=dataAccess;
}
// to do : Implement methods of your ISendService interface.
// you may use this.dataAccess in those methods as needed.
}
In your unit tests, you can create a mock implementation of your interfaces which returns static data instead of accessing the database.
For example, If you are using Moq mocking framework, you can do this.
var m = new Mock<IDataAccess>();
var m.Setup(s=>s.GetName(It.IsAny<int>())).Returns("Test");
var s = new SendService(m);
var result= s.SomeMethod();

How to pass Interface as parameter for Controller class in Substitute

I am new to nSubstitute. And I am writing test method for my controller class. I have a TestMethod called GetDefaultStateTest() which having Substitute class as shown below
[TestMethod]
public void GetDefaultStateTest()
{
var _GetDefaultState = Substitute.For<CustomerController>(ICustomer cus);
Assert.IsNotNull(_GetDefaultState.GetDefaultState());
}
Because my controller class having parameterized constructor as below.
public class CustomerController : Controller
{
private readonly ICustomer _customer;
public CustomerController(ICustomer customer)
{
_customer = customer;
}
public string GetDefaultState()
{
// Get default state from settings table
List<tblSettings> settings = new List<tblSettings>();
// Calling service method GetSettings
settings = _customer.GetSettings();
var defaultState = from setting in settings
where setting.Desc == "DefaultState"
select setting.Settings;
string strState = "";
foreach (var oState in defaultState)
{
strState = oState;
break;
}
return strState;
}
}
While run the test method, it raise null reference issue. Because of parameter ICustomer is null
var _GetDefaultState = Substitute.For<CustomerController>(ICustomer cus);
How to resolve this problem.
If you are testing your controller class then you do not want to substitute for it, you want to use a real one (otherwise you'd just be testing a fake object "works" :)). Where you may want to substitute is for that class's dependencies, in this case, ICustomer.
[TestMethod]
public void GetDefaultStateTest()
{
var customer = Substitute.For<ICustomer>();
var controller = new CustomerController(customer);
Assert.IsNotNull(controller.GetDefaultState());
}
You may then want to fake out the ICustomer.GetSettings() method so you can test what your controller does with that data:
[TestMethod]
public void GetDefaultStateTestFromSettings()
{
var customer = Substitute.For<ICustomer>();
customer.GetSettings().Returns(somethingSensible);
var controller = new CustomerController(customer);
Assert.AreEqual(expectedDefaultState, controller.GetDefaultState());
}
As an aside, sometimes it makes more sense to use real objects (say, a real implementation of ICustomer) rather than substitutes. This will depend on how well-defined the interactions with the dependencies are, where you want to define the boundaries of your system under test, and how much confidence the test gives you that the system under test is working correctly. Or put more simply, whatever makes it easy and reliable to test. :)
Hope this helps.

Test if save method is hit in unit test

I'm starting with unit testing in the asp.net mvc 4 framework.
I got a repository with basic crud methods and a save method. When I create a unit test I create a test repository and test if e.g. a item to the collection is added. That all goes smoothly but I cannot test if the save method is hit.
I tried to add a boolean property to the test repository which will be set to true if .save() is hit. But then I need to change the interface, and also the database repository. Which is in my opinion neither practical nor best practice.
What is the best method to test this? Thank you in advance for your answer.
My code:
the fake repository:
public class TestUserRepository : IUserManagementRepository
{
/// <summary>
/// entries used used for testing
/// </summary>
private List<User> _entities;
/// <summary>
/// constructor
/// </summary>
public TestUserRepository()
{
_entities = new List<User>();
_entities.Add(new User
{
Id = 1,
InsertDate = DateTime.Now,
LastUpdate = DateTime.Now,
Username = "TestUserName",
Password = "TestPassword"
});
}
...
public void Create(User task)
{
_entities.Add(task);
}
public void Save()
{
//do nothing
}
}
the controller to test:
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
_repository.Create(user);
_repository.Save();
return RedirectToAction("Index");
}
else
{
return View(user);
}
}
and the test
[TestMethod()]
public void CreateTest()
{
IUserManagementRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
}
You must be careful not to write a bunch of unit tests that just test your test repository.
Consider the following scenario:
You have a service method, that is supposed to add an item to your repository.
Your unit test calls this method, and you should verify that the appropriate "AddX" method was called on the repository.
This is a valid unit test scenario, to test it you can use your test repository. Since it is your test object, you have full control over it. You can expose properties such as "AddXMethodCallCount" or something similar.
Over time you will find yourself writing a lot of test code that is pretty much boilerplate. The alternative, which I strongly recommend, is to use a mocking framework:
https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use
It takes some getting used to, but once you get it, it will speed up your unit testing significantly.
If you don't want to use mocking yet, but want to still achieve your goal of verifying whether or not Save() is called, I would suggest just adding a publicly exposed SaveMethodCallCount property:
public class TestUserRepository : IUserManagementRepository
{
...
public SaveMethodCallCount {get; set;}
...
public void Save()
{
SaveMethodCallCount++;
}
}
This works, because in your unit test you can actually say:
TestUserRepository repository = new TestUserRepository();
The UserController does not care, as long as the passed in parameter implements the IUserManagementRepository interface. The controller interacts with the repository object through the interface, but the unit test does not have to, and the TestUserRepository, being a test class, is allowed to have much more functionality, that does not have to be exposed through the interface.
So your test could look something like:
[TestMethod()]
public void CreateTest()
{
TestUserRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
Assert.AreEqual(1, repository.SaveMethodCallCount);
}
To make my example complete, let me show you what this would look like if you used a mocking framework, like Moq. You can see some more examples here. The example test method uses Moq and Arrange/Act/Assert, and tests only one thing - that Save() is called when Create() is called.
[TestMethod()]
public void Test_SaveCalledWhenCreateCalled()
{
// Arrange
// First, instead of creating an instance of your test class, you create a mock repository.
// In fact, you don't need to write any code, the mocking framework handles it.
var mockRepository = new Mock<IUserManagementRepository>();
// and pass the mock repository (which implements the IUserManagementRepository) to your controller
UserController controller = new UserController(mockRepository);
// Act
ActionResult actionResult = controller.Create(user);
// Assert
// see how easy it is to do with a mocking framework:
mockRepository.Verify(rep => rep.Save(), Times.AtLeastOnce());
}

NInject, nHibernate, and auditing in ASP.NET MVC

I am working on an inherited application which makes use of NInject and nHibernate as part of an ASP.NET MVC (C#) application. Currently, I'm looking at a problem with the auditing of modifications. Each entity has ChangedOn/ChangedBy and CreatedOn/CreatedBy fields, which are mapped to database columns. However, these either get filled with the wrong username or no username at all. I think this is because it has been configured in the wrong way, but I don't know enough about nHibernate and NInject to solve the issue, so I hope someone can help. Below some code snippets to hopefully provide sufficient insight in the application.
Creating the session factory and session:
public class NHibernateModule : NinjectModule
{
public override void Load()
{
Bind<ISessionFactory>().ToProvider(new SessionFactoryProvider()).InSingletonScope();
Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
Bind<INHibernateUnitOfWork>().To<NHibernateUnitOfWork>().InRequestScope();
Bind<User>().ToProvider(new UserProvider()).InRequestScope();
Bind<IStamper>().ToProvider(new StamperProvider()).InRequestScope();
}
}
public class SessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
// Create session
var sessionFactory = context.Kernel.Get<ISessionFactory>();
var session = sessionFactory.OpenSession();
session.FlushMode = FlushMode.Commit;
return session;
}
}
public class SessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnectionString"].ToString();
var stamper = context.Kernel.Get<IStamper>();
return NHibernateHelper.CreateSessionFactory(connectionString, stamper);
}
}
public class StamperProvider : Provider<IStamper>
{
protected override IStamper CreateInstance(IContext context)
{
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
System.Security.Principal.IIdentity identity = user == null ? null : user.Identity;
string name = identity == null ? "Unknown" : identity.Name;
return new Stamper(name);
}
}
public class UserProvider : Provider<User>
{
protected override UserCreateInstance(IContext context)
{
var userRepos = context.Kernel.Get<IUserRepository>();
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
System.Security.Principal.IIdentity identity = user == null ? null : user.Identity;
string name = identity == null ? "" : identity.Name;
var user = userRepos.GetByName(name);
return user;
}
}
Configuring the session factory:
public static ISessionFactory CreateSessionFactory(string connectionString, IStamper stamper)
{
// Info: http://wiki.fluentnhibernate.org/Fluent_configuration
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(connectionString))
.Mappings(m =>
{
m.FluentMappings
.Conventions.Add(PrimaryKey.Name.Is(x => "Id"))
.AddFromAssemblyOf<NHibernateHelper>();
m.HbmMappings.AddFromAssemblyOf<NHibernateHelper>();
})
// Register
.ExposeConfiguration(c => {
c.EventListeners.PreInsertEventListeners =
new IPreInsertEventListener[] { new EventListener(stamper) };
c.EventListeners.PreUpdateEventListeners =
new IPreUpdateEventListener[] { new EventListener(stamper) };
})
.BuildSessionFactory();
}
Snippet from the eventlistener:
public bool OnPreInsert(PreInsertEvent e)
{
_stamper.Insert(e.Entity as IStampedEntity, e.State, e.Persister);
return false;
}
As you can see the session factory is in a singleton scope. Therefore the eventlistener and stamper also get instantiated in this scope (I think). And this means that when the user is not yet logged in, the username in the stamper is set to an empty string or "Unknown".
I tried to compensate for this problem, by modifying the Stamper. It checks if the username is null or empty. If this is true, it tries to find the active user, and fill the username-property with that user's name:
private string GetUserName()
{
if (string.IsNullOrWhiteSpace(_userName))
{
var user = ServiceLocator.Resolve<User>();
if (user != null)
{
_userName = user.UserName;
}
}
return _userName;
}
But this results in a completely different user's name, which is also logged in to the application, being logged in the database. My guess this is because it resolves the wrong active user, being the last user logged in, instead of the user that started the transaction.
The offending parts are here:
Bind<ISessionFactory>().
.ToProvider(new SessionFactoryProvider())
.InSingletonScope();
Bind<IStamper>()
.ToProvider(new StamperProvider())
.InRequestScope();
And later on:
public class SessionFactoryProvider : Provider<ISessionFactory>
{
protected override ISessionFactory CreateInstance(IContext context)
{
// Unimportant lines omitted
var stamper = context.Kernel.Get<IStamper>();
return NHibernateHelper.CreateSessionFactory(connectionString, stamper);
}
}
public class StamperProvider : Provider<IStamper>
{
protected override IStamper CreateInstance(IContext context)
{
// Unimportant lines omitted
string name = /* whatever */
return new Stamper(name);
}
}
Let's analyze what's going on with the code:
The ISessionFactory is bound as single-instance. There will only ever be one throughout the lifetime of the process. This is fairly typical.
The ISessionFactory is initialized with SessionFactoryProvider which immediately goes out to get an instance of IStamper, and passes this as a constant argument to initialize the session factory.
The IStamper in turn is initialized by the StamperProvider which initializes a Stamper class with a constant name set to the current user principal/identity.
The net result of this is that as long as the process is alive, every single "stamp" will be assigned the name of whichever user was first to log in. This might even be the anonymous user, which explains why you're seeing so many blank entries.
Whoever wrote this only got half the equation right. The IStamper is bound to the request scope, but it's being supplied to a singleton, which means that only one IStamper will ever be created. You're lucky that the Stamper doesn't hold any resources or have any finalizers, otherwise you'd probably end up with a lot of ObjectDisposedException and other weird errors.
There are three possible solutions to this:
(Recommended) - Rewrite the Stamper class to look up the current user on each call, instead of being initialized with static user info. Afterward, the Stamper class would no longer take any constructor arguments. You can the bind the IStamper InSingletonScope instead of InRequestScope.
Create an abstract IStamperFactory with a GetStamper method, and a concrete StamperFactory which implements it by wrapping the IKernel instance. Bind these together InSingletonScope. Have your concrete factory return kernel.Get<IStamper>(). Modify the session factory to accept and hold an IStamperFactory instead of an IStamper. Each time it needs to stamp, use the factory to get a new IStamper instance.
Change the ISessionFactory to be InRequestScope. Not recommended because it will hurt performance and potentially mess up ID generators if you don't use DB-generated identities, but it will solve your auditing problem.
Aaronaught, you're analysis describes exactly what I suspected. However, I found there is a fourth solution which is easier and more straightforward IMHO.
I modified the sessionprovider, such that the call to OpenSession takes an instance of IInterceptor as argument. As it turns out, the event listeners aren't actually supposed to be used for auditing (a bit of a rant, but other than that he is right, according to Fabio as well).
The AuditInterceptor implements OnFlushDirty (for auditing existing entities) and OnSave (for auditing newly created entities). The SessionProvider looks as below:
public class SessionProvider : Provider<ISession>
{
protected override ISession CreateInstance(IContext context)
{
// Create session
System.Security.Principal.IPrincipal user = HttpContext.Current.User;
System.Security.Principal.IIdentity identity = user == null ? null : user.Identity;
string name = identity == null ? "" : identity.Name;
var sessionFactory = context.Kernel.Get<ISessionFactory>();
var session = sessionFactory.OpenSession(new AuditInterceptor(name));
session.FlushMode = FlushMode.Commit;
return session;
}
}

ASP.NET MVC HttpContext.Session object

I have a question. I've built custom class in my project that contains public static property ctx and assingn HttpContext.Current object to it. In runtime that property seem to reference HttpContext object, but ctx.Session class is null. When i debug my app the left side of an expression (ctx) is not exactly the same as right side (HttpContext.Current). why this is happening?
Grettings
HttpContext.Current is a singleton only for that request. By assigning the HttpContext.Current to a static variable you would be sharing this HttpContext.Current to an entire scope, which may not be right.
Session is a per user object while, static is an application wide object. Use static wisely.
What I would do would be something like this.
1- a static class (ex: ContextFactory) which provides current httpcontext. If it has HttpContext.Current, then is provides that value, if not then it provides an assigned context. In your case, new Mock<HttpContextBase>();
public static class ContextFactory
{
private static HttpContextBase current = null;
public static HttpContextBase Current
{
get { return current ?? HttpContext.Current; }
set { current = value; }
}
}
2- Then I alter the code UserSess to
public static class UserSess
{
public static UserID
{
get { return ContextFactory.Current.Session["UserID"]; }
set { ContextFactory.Current.Session["UserID"] = value; }
}
//...
}
sincerely

Resources