Unit Test a HtmlHelper in ASP.net MVC - c#

I have a HtmlHelper that returns the bootstrap selected class. I use this helper to apply the active state to my menu items.
Helper Code
public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "",
string ccsClass = "selected")
{
var viewContext = html.ViewContext;
var isChildAction = viewContext.Controller.ControllerContext.IsChildAction;
if (isChildAction)
{
viewContext = html.ViewContext.ParentActionViewContext;
}
var routeValues = viewContext.RouteData.Values;
var currentController = routeValues["controller"].ToString();
var currentAction = routeValues["action"].ToString();
if (string.IsNullOrEmpty(controllers))
{
controllers = currentController;
}
if (string.IsNullOrEmpty(actions))
{
actions = currentAction;
}
var acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
var acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();
return acceptedControllers.Contains(currentController) && acceptedActions.Contains(currentAction)
? ccsClass
: string.Empty;
}
Testing Code
[Test]
public void WhenPassedControllerAndActionMatchContextReturnSelectedClass()
{
var htmlHelper = CreateHtmlHelper(new ViewDataDictionary());
var result = htmlHelper.IsSelected("performance", "search");
Assert.AreEqual("selected", result);
}
public static HtmlHelper CreateHtmlHelper(ViewDataDictionary viewData)
{
var mocks = new MockRepository();
var controllerContext = mocks.DynamicMock<ControllerContext>(
mocks.DynamicMock<HttpContextBase>(),
new RouteData(),
mocks.DynamicMock<ControllerBase>());
var viewContext = new ViewContext(controllerContext, mocks.StrictMock<IView>(), viewData, new TempDataDictionary(), mocks.StrictMock<TextWriter>());
//var mockViewContext = MockRepository.GenerateMock<ViewContext>();
var mockViewDataContainer = mocks.DynamicMock<IViewDataContainer>();
mockViewDataContainer.Expect(v => v.ViewData).Return(viewData);
return new HtmlHelper(viewContext, mockViewDataContainer);
}
This is giving me an error. When I debug, I see that it is because ControllerContext is null on Line 5 of Helper code.
What would be the flexible, correct way of testing that code?

I've noticed that your are using rhino-mocks but it possible (and really easy) to solve your problem using Typemock Isolater by faking the dependencies of HtmlHelper as shown in the following example:
[TestMethod, Isolated]
public void WhenPassedControllerAndActionMatchContextReturnSelectedClass()
{
var fakeHtmlHalper = Isolate.Fake.Dependencies<HtmlHelper>();
var fakeViewContext = Isolate.GetFake<ViewContext>(fakeHtmlHalper);
Isolate.WhenCalled(() => fakeViewContext.RouteData.Values["controller"]).WillReturn("performance");
Isolate.WhenCalled(() => fakeViewContext.RouteData.Values["action"]).WillReturn("search");
var result = fakeHtmlHalper.IsSelected("performance", "search");
Assert.AreEqual("selected", result);
}

Related

Xunit in asp.net core

I'm new at asp.net and moq and xunit test, I want to create a test case for my asp.net project. I have the service file that is CRUD action,
I have been written for Create Method it's Ok but at Get, GetAll, Delete, Put method I don't know what should I setup
public void Test1()
{
var tutorRequest = new Mock<ITutorRequestService>();
//What should i set up for Get and GetAll
tutorRequest.Setup(r => r.Get(It.IsAny<int>(), It.IsAny<string?>()))
.ReturnsAsync(() => new Entity());
var logger = new Mock<ILogger<TutorRequestsController>>();
var controller = new TutorRequestsController(tutorRequest.Object, logger.Object);
var rs = controller.Get(1, "");
Assert.NotNull(rs);
}
My service class
public async Task<TutorRequest> Create(TutorRequestModel tutor)
{
var entity = _mapper.Map<TutorRequest>(tutor);
CheckDataNotNull("entity", entity);
entity = await _repository.Add(entity);
return _mapper.Map<TutorRequest>(entity);
}
public async Task<TutorRequest> Delete(int tutorId)
{
var entity = await _repository.Delete(tutorId);
return _mapper.Map<TutorRequest>(entity);
}
public async Task<Entity> Get(int id, string? fields)
{
var entity = await _repository.Get(id);
CheckDataNotNull("tutor request", entity);
var shaped = _dataShaper.ShapeData(entity, fields);
CheckDataNotNull("shaped", shaped);
return _mapper.Map<Entity>(shaped);
}
public PageList<Entity> GetAll(TutorRequestParams param)
{
var listAll = _repository.GetAll();
CheckDataNotNull("shaped", listAll);
Search(ref listAll, param);
var sortedStudent = _sortHelper.ApplySort(listAll, param.OrderBy);
var shapedOwners = _dataShaper.ShapeData(sortedStudent, param.Fields);
return PageList<Entity>.ToPageList(shapedOwners, param.PageNume, param.PageSize);
}
public async Task<TutorRequest> Update(TutorRequestModel tutor)
{
var entity = _mapper.Map<TutorRequest>(tutor);
entity = await _repository.Update(entity);
return _mapper.Map<TutorRequest>(entity);
}
If you're expecting the GetAll method to return something, you need to set up the call for the mocked service.
mockRepo.Setup(r => r.GetAll(It.IsAny<TutorRequestParams>())).Returns(
new PagedList<ExpandoObject>
{
// result you're expecting
}
);
I have write a test case for Get method that similar to your example, you can check it out
public void Test_Get_Method()
{
var questService = new Mock<IQuestService>();
questService.Setup(x => x.Get(It.IsAny<Guid>()))
.ReturnsAsync(new QuestResponseModel()
{
Id = Guid.Empty,
Title = "Test",
Description = "TestDescription",
Price = 100,
Status = "Pending",
AvailableTime = DateTime.Now,
EstimatedTime = "120",
QuestTypeId = 1
});
var mapperMock = new Mock<IMapper>();
var controller = new QuestController(questService.Object);
var result = controller.Get(Guid.Empty);
Assert.Equal("TestDescription", result.Result.Data.Description);
}

How to unit test ViewComponent.Invoke()?

In ViewComponent object, HttpContext and User are read-only properties.
How to unit test such a component?
I'm using the MSTest Freamwork.
The follow properties are used in my code
Cookie
Session
User(System.Security.Principal)
public ViewViewComponentResult Invoke()
{
var vm = new SummaryViewModel();
if (User.Identity is ClaimsIdentity identity && identity.IsAuthenticated)
{
vm.IsAuthenticated = true;
vm.UserName = identity.Claims.FirstOrDefault(c => c.Type == "UserName").Value;
vm.PhotoUrl = identity.Claims.FirstOrDefault(c => c.Type == "FacePicture").Value;
}
return View(vm);
}
[TestMethod]
public void UserSummaryVcTest()
{
var component = new UserSummaryViewComponent();
var model = component.Invoke().ViewData.Model as SummaryViewModel;
Assert.AreEqual("UserName", model.UserName);
}
According to source code the ViewComponent relies on the ViewComponentContext.ViewContext to expose those read only properties, Which in turn accesses the HttpContext. That is your entry point to mock the desired values.
[TestMethod]
public void UserSummaryVcTest() {
// Arrange
var expected = "Username value";
var httpContext = new DefaultHttpContext(); //You can also Mock this
//...then set user and other required properties on the httpContext as needed
var viewContext = new ViewContext();
viewContext.HttpContext = httpContext;
var viewComponentContext = new ViewComponentContext();
viewComponentContext.ViewContext = viewContext;
var viewComponent = new UserSummaryViewComponent();
viewComponent.ViewComponentContext = viewComponentContext;
//Act
var model = viewComponent.Invoke().ViewData.Model as SummaryViewModel;
//Assert
Assert.AreEqual(expected, model.UserName);
}
Here is just a samle for async,
[TestMethod]
public async System.Threading.Tasks.Task InvokeAsyncNameAsync()
{
# setup mocks
...
var httpContext = new DefaultHttpContext();
var viewContext = new ViewContext();
viewContext.HttpContext = httpContext;
var viewComponentContext = new ViewComponentContext();
viewComponentContext.ViewContext = viewContext;
var footerComponent = CreateComponentInstance();
footerComponent.ViewComponentContext = viewComponentContext;
ViewViewComponentResult result = await footerComponent.InvokeAsync() as ViewViewComponentResult;
FooterModel resultModel = (FooterModel)result.ViewData.Model;
....
# do your asserts verifications
Assert.AreEqual(expectedTest, resultModel.FooterText);
}

Unit test webapi controller with response headers

I'm trying to learn webapi and have stumbled across a problem. The training course I was doing showed how to do paging by returning a response header with the next and previous link. However it uses HttpContext.Current.Response.Headers.Add() to send back the next link, previous link, and total pages.
I am also trying to implement unit tests for the controllers. Problem seems to be that the HttpContext.Current is null when running through a unit test. I read somewhere that I shouldn't be HttpContext.Current for webapi as it's not testable, but I'm not sure what I should be using instead.
Here is my contoller code:
public partial class CandidateManagerController
{
private readonly ICandidateManager _candidateManagerV2;
public CandidateManagerController(ICandidateManager candidateManager)
{
_candidateManagerV2 = candidateManager;
}
[VersionedRoute("CandidateManager", 2, Name="CandidateManagerV2")]
public IHttpActionResult Get(int page = 1, int pageSize = 1)
{
try
{
var totalCount = 0;
var totalPages = 0;
var result = _candidateManagerV2.GetCandidates(out totalCount, out totalPages, page, pageSize);
var urlHelper = new UrlHelper(Request);
var prevLink = page > 1
? urlHelper.Link("CandidateManagerV2",
new
{
page = page - 1,
pageSize = pageSize,
})
: "";
var nextLink = page < totalPages ? urlHelper.Link("CandidateManagerV2",
new
{
page = page + 1,
pageSize = pageSize
}) : "";
var paginationHeader = new
{
currentPage = page,
pageSize = pageSize,
totalCount = totalCount,
totalPages = totalPages,
previousPageLink = prevLink,
nextPageLink = nextLink
};
HttpContext.Current.Response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));
return Ok(result);
}
catch (Exception exp)
{
return InternalServerError();
}
}
}
Here is my unit test. Please note I'm using Nunit and Moq:
[TestFixture]
public class CandidateManagerControllerV2Tests
{
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_List_Of_Candidate_Objects()
{
var testList = new List<Candidate>();
testList.Add(new Candidate() { CandidateId = 1, Name = "Mr", Surname = "Flibble" });
testList.Add(new Candidate() { CandidateId = 2, Name = "Arnold", Surname = "Rimmer" });
var totalCount = 0;
var totalPages = 0;
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.GetCandidates(out totalCount, out totalPages, It.IsAny<int>(), It.IsAny<int>())).Returns(testList);
var controller = new CandidateManagerController(mockManager.Object);
SetupControllerForTests(controller);
var result = controller.Get(1, 1);
}
private static void SetupControllerForTests(ApiController controller)
{
var config = new HttpConfiguration();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/candidatemanager");
var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "products" } });
controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
controller.ActionContext=new HttpActionContext();
}
}
I'm hoping someone will be able to help me. It could be that I've been led down a wrong path with the way to implement paging. However it is likely that I'd need to add a response header for something any way.
You should avoid coupling yourself to HttpContext.
Here is another approach to how you can set the header and still be able to unit test it as you intended. You create a HttpResponseMessage, add headers as needed and then create a ResponseMessageResult from it:
//...code removed for brevity
var response = Request.CreateResponse(HttpStatusCode.OK, result);
response.Headers.Add("X-Pagination", Newtonsoft.Json.JsonConvert.SerializeObject(paginationHeader));
IHttpActionResult ok = ResponseMessage(response);
return ok;
You should also note that your controller setup will cause a null reference error when creating your UrlHelper because you are resetting the controller's Request to null when you assign the default ActionContext
private static void SetupControllerForTests(ApiController controller) {
var config = new HttpConfiguration();
var request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/api/candidatemanager");
var route = config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
var routeData = new HttpRouteData(route, new HttpRouteValueDictionary { { "controller", "products" } });
controller.ControllerContext = new HttpControllerContext(config, routeData, request);
controller.Request = request;
controller.Request.Properties[HttpPropertyKeys.HttpConfigurationKey] = config;
//commented this out as it was causing Request to be null
//controller.ActionContext=new HttpActionContext();
}
The following test passed when checking for the X-Pagination header
public async Task Should_Return_Paged_List_Of_Candidate_Objects() {
//Arrange
var testList = new List<Candidate>();
testList.Add(new Candidate() { CandidateId = 1, Name = "Mr", Surname = "Flibble" });
testList.Add(new Candidate() { CandidateId = 2, Name = "Arnold", Surname = "Rimmer" });
var totalCount = 0;
var totalPages = 0;
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.GetCandidates(out totalCount, out totalPages, It.IsAny<int>(), It.IsAny<int>())).Returns(testList);
var controller = new CandidateManagerController(mockManager.Object);
SetupControllerForTests(controller);
//Act
var response = await controller.Get(1, 1).ExecuteAsync(System.Threading.CancellationToken.None);
//Assert
Assert.IsNotNull(response);
Assert.IsInstanceOfType(response, typeof(HttpResponseMessage));
Assert.IsTrue(response.Headers.Contains("X-Pagination"));
}
To test your response headers you need to do the following:
Initialize your controller with a ControllerContext in TestInitialize
Call the controller where you add the custom header
Assert it in the TestMethod
It only works if you add your header in the controller class: HttpContext.Response.Headers.Add("x-custom-header", "value");
Example:
public class MyControllerTests
{
private MyController _controller;
[TestInitialize]
public void Setup()
{
_controller= new MyController();
_controller.ControllerContext = new ControllerContext()
{
HttpContext = new DefaultHttpContext(),
};
}
[TestMethod]
public async Task GetAsyncShouldContainCutomHeader()
{
// Act
await _controller.GetAsync().ConfigureAwait(false);
// Assert
Assert.IsTrue(_controller.Response.Headers.ContainsKey("x-custom-header"));
Assert.IsTrue(_controller.Response.Headers["x-custom-header"].Equals("value"));
}
}

Is there a way to generate Urls with WebAPI?

POST EDITED BELOW
We can't figure out why UrlHelper is returning null strings when used from the WebApi controller's context.
We've done the neccesary debugging but we can't find out why this happens, the RouteData has the routes in it but it doesn't seem to be working.
For the most part, we use a RenderViewToString function, which loads views that consist of calls to Url.RouteUrl(routeName).
Something that's been tried is creating a custom UrlHelper (but to no avail) and debugging with either UrlHelper's (MVC / HTTP).
Attribute routing is used everywhere with route names.
Example usage code:
public class WebApiController : BaseApiController
{
[HttpPost]
[ResponseType(typeof(string))]
[Route("cart/get/checkout", Name = "api.cart.get.checkout")]
public IHttpActionResult GetCheckOutShoppingCart([FromBody] string data)
{
return Ok(RenderViewToString("CartController", "_CheckOutCartPartial", new ShoppingCartModel(Auth.IsAuthenticated ? Auth.GetCustomer().DefaultShippingInfo.CountryId : 148)
{
AddInsurance = false,
InsuredShipping = insuredShipping,
CurrentDeliveryMethodId = deliveryMethodId,
CurrentPaymentMethodId = paymentMethodId
}));
}
}
BaseApiController class:
public class BaseApiController : ApiController
{
public static string RenderViewToString(string controllerName, string viewName)
{
return RenderViewToString(controllerName, viewName, new Dictionary<string, object>());
}
public static string RenderViewToString(string controllerName, string viewName, object model)
{
using (var writer = new StringWriter())
{
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext =
new ControllerContext(
new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null),
new HttpResponse(null))), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View,
new ViewDataDictionary(model), new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
public static string RenderViewToString(string controllerName, string viewName, Dictionary<string, Object> data)
{
using (var writer = new StringWriter())
{
var viewData = new ViewDataDictionary();
foreach (var kv in data)
{
viewData[kv.Key] = kv.Value;
}
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName);
var fakeControllerContext =
new ControllerContext(
new HttpContextWrapper(new HttpContext(new HttpRequest(null, "http://google.com", null),
new HttpResponse(null))), routeData, new FakeController());
var razorViewEngine = new RazorViewEngine();
var razorViewResult = razorViewEngine.FindView(fakeControllerContext, viewName, "", false);
var viewContext = new ViewContext(fakeControllerContext, razorViewResult.View, viewData,
new TempDataDictionary(), writer);
razorViewResult.View.Render(viewContext, writer);
return writer.ToString();
}
}
private class FakeController : ControllerBase
{
protected override void ExecuteCore()
{
}
}
}
EDIT
We've put together a class that should in theory work, but it doesn't.
The RouteData has both the MVC and API routes in the collection.
public static class Url
{
public static bool IsWebApiRequest()
{
return
HttpContext.Current.Request.RequestContext.HttpContext.CurrentHandler is
System.Web.Http.WebHost.HttpControllerHandler;
}
public static string RouteUrl(string routeName, object routeValues = null)
{
var url = String.Empty;
try
{
if (IsWebApiRequest())
{
var helper = new System.Web.Http.Routing.UrlHelper();
url = helper.Link(routeName, routeValues);
}
else
{
var helper = new System.Web.Mvc.UrlHelper();
url = helper.RouteUrl(routeName, routeValues);
}
return url;
}
catch
{
return url;
}
}
public static string HttpRouteUrl(string routeName, object routeValues = null)
{
var url = String.Empty;
try
{
if (IsWebApiRequest())
{
var helper = new System.Web.Http.Routing.UrlHelper();
url = helper.Link(routeName, routeValues);
}
else
{
var helper = new System.Web.Mvc.UrlHelper();
url = helper.HttpRouteUrl(routeName, routeValues);
}
return url;
}
catch
{
return url;
}
}
}
This issue has been resolved by building a custom UrlHelper class, which looks into the RouteTable and then returns the url with the patterns replaced.
public static class Link
{
public static string RouteUrl(string routeName, object routeValues = null)
{
var url = String.Empty;
try
{
var route = (Route)RouteTable.Routes[routeName];
if (route == null)
return url;
url = "~/".AbsoluteUrl() + route.Url;
url = url.Replace("{culture}", System.Threading.Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.ToLower());
if (routeValues == null)
return url;
var values = routeValues.GetType().GetProperties();
Array.ForEach(values, pi => url = Regex.Replace(url, "{" + pi.Name + "}", pi.GetValue(routeValues, null).ToString()));
return url;
}
catch
{
var newUrl = RouteUrl("403");
if(newUrl == String.Empty)
throw;
return newUrl;
}
}
public static string HttpRouteUrl(string routeName, object routeValues = null)
{
return RouteUrl(routeName, routeValues);
}
}
Try Uri.Link(routeName, object)
var uri = Url.Link("api.cart.get.checkout", new { id = 1 });
This will inject the given object's properties into the route if the property name matches a route parameter.
WebApi is not MVC. Even though it looks very similar, it's a completely different system.
UrlHelper (which is MVC) will be looking at the MVC route table, and ignore any WebApi routes.
Try creating the route the hard way, essentially hard-coding the controller and action names into the views. :-(
OK, based on your comment, it seems that you're trying to call your Url.RouteUrl(string routeName, object routeValues = null) or Url.HttpRouteUrl(string routeName, object routeValues = null) from your MVC layout.cshtml file.
If that's the case, the Url.IsWebApiRequest() would return false because the layout.cshtml file is only processed as part of handling MVC request and not WebAPI. That will cause the url generation methods to use MVC route collection instead of the WebAPI collection.
Change your Url class so that RouteUrl always builds WebAPI url and HttpRouteUrl only builds MVC url then in your layout file use proper method based on which kind of url you need in the particular context.
public static class Url
{
public static bool IsWebApiRequest()
{
return
HttpContext.Current.Request.RequestContext.HttpContext.CurrentHandler is
System.Web.Http.WebHost.HttpControllerHandler;
}
public static string RouteUrl(string routeName, object routeValues = null)
{
var url = String.Empty;
try
{
var helper = new System.Web.Http.Routing.UrlHelper();
return helper.Link(routeName, routeValues);
}
catch
{
return url;
}
}
public static string HttpRouteUrl(string routeName, object routeValues = null)
{
var url = String.Empty;
try
{
var helper = new System.Web.Mvc.UrlHelper();
return helper.HttpRouteUrl(routeName, routeValues);
}
catch
{
return url;
}
}
}

Mocking HttpContext.GetGlobalResourceObject() returns null

need your help in mocking HttpContext.GetGlobalResourceObject() so i can unit test my helper class . I could mock the HttpContextBase but for some reason when debugging the unit test the
HttpContext.GetGlobalResourceObject() is always null ( noticed HttpContext.Current is null ). How do i fix this issue ?
Here is my static HelperClass
public static class HtmlHelperExtentions
{
public static string GetBrandedCssBundle(this HtmlHelper htmlHelper)
{
return "BrandTest";
}
public static HtmlString Translate(this HtmlHelper htmlhelper, string defaultString, string key, params object[] objects)
{
var resource = HttpContext.GetGlobalResourceObject(null, key);
if (resource != null)
{
defaultString = resource.ToString();
}
return objects.Length > 0 ? new HtmlString(string.Format(defaultString, objects)) : new HtmlString(defaultString);
}
}
Here are my unit tests
[TestClass]
public class HtmlHelperTest
{
Mock<HttpContextBase> contextBase {get;private set;};
[TestInitialize()]
public void Initializer()
{
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(ctx => ctx.Identity).Returns(identity.Object);
identity.Setup(id => id.IsAuthenticated).Returns(true);
identity.Setup(id => id.Name).Returns("test");
context.Setup(ctx => ctx.Response.Cache).Returns(CreateCachePolicy());
contextBase = context;
}
[TestCleanup]
public void TestCleanup()
{
HttpContext.Current = null;
}
[TestMethod]
[TestCategory(TestCategoryType.UnitTest)]
public void HtmlHelperExtentions_Translate_WithValidInputs_ReturnsTranslatedContent()
{
// Arrange
var defaultstring = "TestMessage";
var inputkey = "XX.Areas.Onboarding.{0}Messages.Message_Onboarding_XX_1001";
var expectedvalue = "HolaMessage";
HtmlHelper htmlhelper = null;
contextBase.Setup(ctx => ctx.GetGlobalResourceObject(null,
inputkey)).Returns(expectedvalue);
//Act
var result = HtmlHelperExtentions.Translate(htmlhelper, null, inputkey);
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedvalue, result.ToString());
}
}
The problem in your code above is, although you are setting up HttpContextBase its not connected with you code. So when the actual call made in your Translate method, the HttpContext is not what you mocked hence returning null always.
Since its a standalone class, setting up HttpContext is difficult. If this code is been invoked from a controller it would have been possible to write
controller.ControllerContext = myMockedContext;
To fix this problem, you could work on the lines of solution provide by Mr. Joe in his answer, you could change your static helper class method something like this, injecting the HttpContextBase object:
public static HtmlString Translate(this HtmlHelper htmlhelper, HttpContextBase contextBase, string defaultString, string key, params object[] objects)
{
var resource = contextBase.GetGlobalResourceObject(null, key);
if (resource != null)
{
defaultString = resource.ToString();
}
return objects.Length > 0 ? new HtmlString(string.Format(defaultString, objects)) : new HtmlString(defaultString);
}
And from your test you could pass mocked contextBase object like so:
[TestMethod]
public void HtmlHelperExtentions_Translate_WithValidInputs_ReturnsTranslatedContent()
{
// Arrange
var defaultstring = "TestMessage";
var inputkey = "XX.Areas.Onboarding.{0}Messages.Message_Onboarding_XX_1001";
var expectedvalue = "HolaMessage";
HtmlHelper htmlhelper = null;
contextBase.Setup(ctx => ctx.GetGlobalResourceObject(null, inputkey)).Returns(expectedvalue);
//Act
var result = HtmlHelperExtentions.Translate(htmlhelper, contextBase.Object, defaultstring, inputkey);
//Assert
Assert.IsNotNull(result);
Assert.AreEqual(expectedvalue, result.ToString());
}

Categories