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() ?
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 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.
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