I don't understand how you would test something like the following controller.
How would you mock Request? It seems to me that to mock it you would need to pass in a Request to the method but that is wrong. Or you would need to inject it into the Controller constructor but that seems wrong too.
I totally get how this would work with ISomethingService or ISomethingRepository but for intrinsic dependancies I just don't get it.
Thanks
public ActionResult Test()
{
return View(Request.Browser.Crawler ? "A" : "B");
}
you need to create a mock http context. there are multiple libraries to do so, but you basically need to do something like this:
var request = new HttpRequest("", "http://localhost/", "");
var writer = new StringWriter();
var response = new HttpResponse(writer);
var context = new HttpContext(request, response);
Related
I have the following code that I need to unit test:
public ActionResult VerifyVoucherCode()
{
var model = new VerifyVoucherModel();
model.Voucher = Request.GetFirstQueryValue("token", "voucher");
The second line here is where my test fails. The code for this method is:
public static string GetFirstQueryValue(this HttpRequestBase request, params string[] keys)
{
return request.QueryString.GetFirstValue(keys);
}
My attempt to unit test this part of the method so far is:
var httpContext = CreateHttpContext();
var httpRequestBase = new HttpRequestWrapper(httpContext.Request);
var nameValueCollection = new NameValueCollection();
var controller = CreateMvcController<SignUpController>();
MockActivationCodeHelper(validationResult, controller);
For reference, the CreateHttpContext method is:
private HttpContext CreateHttpContext()
{
var httpContext = new HttpContext(
new HttpRequest("", "http://tempuri.org", "token=123"),
new HttpResponse(new StringWriter())
);
return httpContext;
}
It fails here return request.QueryString.GetFirstValue(keys); with a System Not Implemented exception for Query String. Any pointers here please?
Please take a look at flurl, while it may require some refactoring to your code, using it allows to construct http requests in a very handy and fluent way. Moreover, it makes testing your business logic that depends on calling external HTTP services extremely easy (event for edge cases)
The library has good documentation and his author is very responsive on stackoverflow.
Check out: https://flurl.dev/
How can I mock HttpContext.Current.Request.Form["something"] data in the tested controller? I can mock HttpContext.Current and it works but Request is readonly. I can not change the implementation of the controller where the Form data is used. I only have to write a test.
If you really can't change the implementation of the controller to use modelbinding, you can mock the request object easily enough:
var formData = new FormCollection(new Dictionary<string, Microsoft.Extensions.Primitives.StringValues> { { "test", "value" } });
var requestMock = new Mock<HttpRequest>();
requestMock.SetupGet(x => x.Form).Returns(formData);
var contextMock = new Mock<HttpContext>();
contextMock.SetupGet(x => x.Request).Returns(requestMock.Object);
Setup FormCollection how you need your example data to look.
As others have stated, it makes way more sense to use modelbinding since it abstracts away this requirement.
Actually, you didn't mention if you were using ASP.NET or Core, I assume .NET based on HttpContext.Current?
I have a controller method in my webapi project which calls a service method and converts the response of the service method into a Dto object for sending the response.
The controller looks something like this:
[HttpPost]
[Route(WebApiConfig.RootApiUri + "/v1/examplepost")]
public async Task<List<Html1Dto>> examplepost([FromBody] SomeInfoDto someInfoDto)
{
var someInfo = _mapper.Map<SomeInfoDto, SomeInfo>(someInfoDto);
return this._mapper.Map<List<Html1>, List<Html1Dto>>(await this._someService.SomeCall(someInfo));
}
and the mock test like this :
//Arrange
var mockMapper = new Mock<IMapper>();
var mockSomeService = new Mock<ISomeService<Html1>>();
mockSomeService.Setup(s => s.SomeCall(It.IsAny<SomeInfo>())).ReturnsAsync(
new List<Html1>() {new Html1() {....}});
SomeInfoDto mockSomeInfoDto = new SomeInfoDto()
{
..
};
SomeInfo mockSomeInfo = new SomeInfo();
mockMapper.Setup(m => m.Map<SomeInfoDto, SomeInfo>(mockSomeInfoDto))
.Returns(mockSomeInfo);
mockMapper.Setup(m => m.Map<List<Html1>, List<Html1Dto>>(It.IsAny<List<Html1>>())).Returns(It.IsAny<List<Html1Dto>>);
var someController = GetController(mockMapper.Object, mockSomeService.Object);
//Act
var result = await someController.examplePost(mockSomeInfoDto);
I am using automapper to map the objects with Dtos. When I debug this test, result comes as null. The mapping of incoming dto works fine. I suspect there is some issue with the service method setup. Anyhelp is appreciated.
Your mapper mock is the other way round
mockMapper.Setup(m => m.Map<List<Html1>, List<Html1Dto>>(It.IsAny<List<Html1>>())).Returns(It.IsAny<List<Html1Dto>>);
to the signature in the method
this._mapper.Map<List<Html1Dto>, List<Html1>>(await this._someService.SomeCall(someInfo));
Additionally, assuming that is correct in your actual code, then the other bit that could be causing you issue is that the return It.IsAny<List<Html1Dto>> which will be null as default(List<HtmlDto>) is null, return a concrete class there instead as below.
This call:
this._mapper.Map<List<Html1Dto>, List<Html1>>(await this._someService.SomeCall(someInfo));
Doesn't have a setup in the Unit Test, so will return null. You need to arrange that to, probably something like:
mockMapper.Setup(m => m.Map<List<Html1Dto>, List<Html1>>(It.IsAny<List<Html1>>()))
.ReturnsAsync(new List<Html1Dto> { ... });
I'm creating a really simple ViewResult subclass called JavaScriptViewResult that, when executing, calls the base implementation and then sets the Content-Type of the response to text/javascript. In trying to unit test this class, I'm running across a slew of difficulties fulfilling all of the dependencies of the ASP.NET MVC stack.
Here is what my unit test, which uses Rhino, looks like so far:
[TestMethod]
public void TestExecuteAction()
{
var request = MockRepository.GenerateMock<HttpRequestBase>();
request.Expect(m => m.Url).Return(new Uri("/Test/JavaScript", UriKind.Relative));
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect(m => m.Request).Return(request);
var controller = MockRepository.GenerateMock<ControllerBase>();
var virtualPathProvider = MockRepository.GenerateMock<VirtualPathProvider>();
var routeCollection = new RouteCollection(virtualPathProvider);
routeCollection.MapRoute("FakeRoute", "Test/JavaScript", new { controller = "Test", action = "JavaScript" });
var routeData = routeCollection.GetRouteData(httpContext);
var context = new ControllerContext(httpContext, routeData, controller);
var viewResult = new JavaScriptViewResult();
viewResult.ExecuteResult(context);
Assert.AreEqual("text/javascript", context.HttpContext.Response.ContentType);
}
The latest exception when running the test is a NullReferenceException deep within the bowels of System.Web.Routing.Route.GetRouteData(HttpContextBase httpContext).
How do I set up all of the dependencies for executing a ViewResult? Are there any techniques for making this simpler? Alternately, is there a different way I can utilize the MVC view engine to generate JavaScript that will set the proper Content-Type for the response?
I figured out how to meet the minimum requirements of ViewResult. One problem I was encountering was mocking the process of finding the view. This was avoidable by ensuring that the View property of my object was populated. Here is my working test:
[TestMethod]
public void TestExecuteAction()
{
var response = MockRepository.GenerateStub<HttpResponseBase>();
response.Output = new StringWriter();
var httpContext = MockRepository.GenerateMock<HttpContextBase>();
httpContext.Expect(m => m.Response).Return(response);
var routeData = new RouteData();
routeData.Values.Add("action", "FakeAction");
var context = new ControllerContext(httpContext, routeData, MockRepository.GenerateMock<ControllerBase>());
var viewResult = new JavaScriptViewResult();
viewResult.View = MockRepository.GenerateMock<IView>();
viewResult.ExecuteResult(context);
Assert.AreEqual("text/javascript", context.HttpContext.Response.ContentType);
}
As suggested by (among others) Kazi Manzur Rashid in this blog post, I am using ActionFilterAttributes to transfer model state from one request to another when redirecting.
However, I find myself unable to write a unit test that test the behavior of these attributes. As an example, this what I want the test for the ImportModelStateAttribute to do:
Setup the filterContext so that TempData[myKey] contains some fake "exported" ModelState (that is, a ModelStateDictionary I create myself, and add one error to)
Make ModelState contain one model error.
Call OnActionExecuting.
Verify the two dictionaries are merged, and ModelState now contains both errors.
I'm at a loss already on the first step.
EDIT:
Yes, I've tried mocking ActionFilterAttribute with Moq, but I get errors stating
Invalid setup on non-overridable member
for both TempData and ModelState.
Tomas, You do not have to mock the filterContext, you can create the real object for testing the action filter, the same goes for the model state, these are poco objects. Only thing that you have to mock is the HttpContext (if needed).
[Fact]
public void Should_import_complete_view_data()
{
var attribute = new ImportViewDataFromTempDataAttribute();
var httpContext = new Mock<HttpContextBase>();
var requestContext = new RequestContext(httpContext.Object, new RouteData());
var previousModel = new object();
var previousViewData = new ViewDataDictionary(previousModel) {{"foo", "bar"}};
previousViewData.ModelState.AddModelError("foo", "bar");
var controller = new Mock<ControllerBase>();
controller.Object.ViewData = new ViewDataDictionary();
controller.Object.TempData = new TempDataDictionary { { attribute.Key, previousViewData } };
var controllerContext = new ControllerContext(requestContext, controller.Object);
var actionContext = new ActionExecutingContext(controllerContext, new Mock<ActionDescriptor>().Object, new Dictionary<string, object>());
attribute.OnActionExecuting(actionContext);
Assert.True(actionContext.Controller.ViewData.ContainsKey("foo"));
Assert.True(actionContext.Controller.ViewData.ModelState.ContainsKey("foo"));
Assert.Same(previousModel, actionContext.Controller.ViewData.Model);
}