In my previous post I explain how to create advance routing system.but testing is one of thing that need in each and every step of application life cycle.so my this post show you how to test a routes easily using unit testing.
In web application all things begin with HttpContext.as Unit test is not a web application it does not use HttpContext but for testing route routes system need a URL and it ask for HttpContext.Request.AppRelativeCurrentExecutionFilePath.for that we have to create mock for HttpRequest,HttpResponse and we overrides a request for this property in HttpContextBase with mock of HttpRequestBase and HttpResponseBase. we use Moq tool for create mock of this classes.
Private Function CreateHttpContext(Optional targerUrl As String = Nothing, Optional HttpMethod As String = "GET") As HttpContextBase
'create mock request
Dim mockRequest As New Mock(Of HttpRequestBase)
mockRequest.Setup(Function(r) r.AppRelativeCurrentExecutionFilePath).Returns(targerUrl)
mockRequest.Setup(Function(r) r.HttpMethod).Returns(HttpMethod)
'create mock response
Dim mockResponse As New Mock(Of HttpResponseBase)
mockResponse.Setup(Function(r) r.ApplyAppPathModifier(It.IsAny(Of String))).Returns(Of String)(Function(s) s)
'create httpMockContext using request and response mock
Dim mockHttpContext As New Mock(Of HttpContextBase)
mockHttpContext.Setup(Function(r) r.Request).Returns(mockRequest.Object)
mockHttpContext.Setup(Function(r) r.Response).Returns(mockResponse.Object)
Return mockHttpContext.Object
End Function
Above function return fake copy of HttpContextBase class.first we have overrides the request for AppRelativeCurrentExecutionFilePath property of HttpRequestBase with user define URL values, and HttpMethod with the Optional GET string value. we have created Mock of HttpResponseBase it just simply return combined url with session id.don't be confuse with this it doesn't make much sense to our testing. and in the last we have just mock HttpContextBase and overrides the property Request,Response with our mocked HttpRequestBase,HttpResponseBase object.
when data is extracted from URL we have to check that extracted values that we expect.for that we have to create function so it can compare the route data with values we expect.
Private Function TestIncomingRouteResult(ByVal rd As RouteData, ByVal controller As String, ByVal action As String, Optional properties As Object = Nothing) As Boolean
Dim valCompare As Func(Of String, String, Boolean) = Function(p1 As String, p2 As String)
Return (StringComparer.InvariantCultureIgnoreCase.Compare(p1, p2) = 0)
End Function
Dim result As Boolean = valCompare(rd.Values("controller"), controller) And valCompare(rd.Values("action"), action)
If properties IsNot Nothing Then
Dim propinfo() As PropertyInfo = properties.GetType.GetProperties
For Each pi In propinfo
If Not (rd.Values.ContainsKey(pi.Name) And valCompare(rd.Values(pi.Name), pi.GetValue(properties, Nothing))) Then
result = False
Exit For
End If
Next
End If
Return result
End Function
In Above code first we check for controller and action values of RouteData is matched with the values that we passed as a parameter. after that we check for the extra parameters that we passed using URL like Query String or id value. any of this comparison get failed function return false and test get failed.
for testing purpose we have created two method. one for check Route should matched and another for checking that route should failed.
Public Sub TestRouteMatch(ByVal url As String, ByVal controller As String, ByVal action As String, Optional routeProperties As Object = Nothing, Optional httpMethod As String = "GET")
'Arrange
Dim routes As New RouteCollection
MvcApplication.RegisterRoutes(routes)
'Act
Dim data As RouteData = routes.GetRouteData(CreateHttpContext(url, httpMethod))
'Assert
Assert.IsNotNull(data)
Assert.IsTrue(TestIncomingRouteResult(data, controller, action, routeProperties))
End Sub
Public Sub TestRouteFail(ByVal url As String, Optional ByVal httpmethod As String = "GET")
'arrange
Dim routes As New RouteCollection
MvcApplication.RegisterRoutes(routes)
'Act
Dim data As RouteData = routes.GetRouteData(CreateHttpContext(url, httpmethod))
'Assert
Assert.IsTrue(data Is Nothing OrElse data.Route Is Nothing)
End Sub
In both of above method first we force MVC to register available routes.next we create mocked HttpContext using URL and HttpMethod and pass it to GetRouteData function of RouteCollection. and we check for the data that is extracted from the URL using method TestIncomingRouteResult.depend on the result of that method Test get Pass or Fail.
Below route definition and testing is just for your reference purpose of how to test routes with above mechanism.because for real testing you have to check route one by one by commenting some other routes.
Public Sub TestIncomingRoutes()
TestRouteMatch("~/RouteTest/Index", "RouteTest", "Index") 'Match by R1,R2
TestRouteMatch("~/", "RouteTest", "Index") 'by R2
TestRouteFail("~/RouteTest/Index/Segment")
TestRouteFail("~/RouteTest") 'passed if R1 route is not present
'route with url segment
TestRouteMatch("~/", "RouteTest", "Index", New With {.id = "someValue"}) 'match by R7
TestRouteMatch("~/RouteTest", "RouteTest", "Index", New With {.id = "somevalue"}) 'match by R7
TestRouteMatch("~/RouteTest/Index", "RouteTest", "Index", New With {.id = "somevalue"}) 'match by R7
TestRouteMatch("~/RouteTest/Index/somevalue", "RouteTest", "Index", New With {.id = "somevalue"}) 'match by R7
TestRouteFail("~/RouteTest/Index/somevalue/somevalue2") 'not match by R7
End Sub
'define routes in global.asax
Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.MapRoute("R2", "{controller}/{action}", New With {.controller = "RouteTest", .action = "Index"})
routes.MapRoute("R1", "{controller}/{action}", New With {.action = "Index"})
routes.MapRoute("R7", "{controller}/{action}/{id}", New With {.controller = "RouteTest", .action = "Index", .id = "somevalue"})
End Sub

0 comments:
Post a Comment
Write your review about this post.