Introduction
In my previous post I made a Plantsmodule which had 2 routes. One of those routes had a problem when tried to put a string in the parameter and that was less than optimal. It was time for tests to make it easier on myself to test these kinds of things.
The module
So here is my module.
Imports WebApplication2.Model
Imports Nancy
Public Class PlantsModule
Inherits NancyModule
Public Sub New()
MyBase.Get("/plants") = Function(parameters)
Return View(New PlantsModel() With {.Plants = New List(Of PlantModel) From {New PlantModel() With {.Id = 2, .Name = "test"}}})
End Function
MyBase.Get("/plants/{Id}") = Function(parameters)
If parameters.id = 1 Then
Return View(New PlantModel() With {.Id = 1, .Name = "test"})
Else
Return View(New PlantModel() With {.Id = 2, .Name = "test"})
End If
End Function
End Sub
End Class```
This one throws an exception when you enter abc or any other bad value.
## The tests
To begin with you should nuget the Nancy.Testing package.
Then you can use the Browser.
For our purpose it would look something like this.
```vbnet
Private _browser As Browser
<SetUp()>
Public Sub FixtureSetup()
Dim configuration = A.Fake(Of IRazorConfiguration)()
Dim bootstrapper = New ConfigurableBootstrapper(Sub(config)
config.Module(Of PlantsModule)()
config.ViewEngine(New RazorViewEngine(configuration))
End Sub)
_browser = New Browser(bootstrapper)
End Sub```
So we tell it what Module to use and we tell it what Engine to use. We also use FakeItEasy to make a mock for our RazorConfiguration. For the next part I got some help from [this blogpost by Jef Claes][2].
if you leave out the Engine you will get this error.
> System.Exception : ConfigurableBootstrapper Exception
> —-> Nancy.RequestExecutionException : Oh noes!
> —-> Nancy.ViewEngines.ViewNotFoundException : Unable to locate view ‘Plants’
> Currently available view engine extensions: sshtml,html,htm
> Locations inspected: ,,,,views/Plants/Plants,Plants/Plants,views/Plants,Plants
> Root path: E:UserschristiaanAppDataLocalNCrunch708461WebApplication2bin
Do you notice how it does not mention cshtml or vbhtml in view engine extensions? That is solved by telling it what engine to use.
In theory that should work but you will get this error when you try it.
> System.Exception : ConfigurableBootstrapper Exception
> —-> Nancy.RequestExecutionException : Oh noes!
> —-> Nancy.ViewEngines.ViewNotFoundException : Unable to locate view ‘Plants’
> Currently available view engine extensions: sshtml,html,htm,cshtml,vbhtml
> Locations inspected: ,,,,views/Plants/Plants,Plants/Plants,views/Plants,Plants
> Root path: E:UserschristiaanAppDataLocalNCrunch708461WebApplication2bin
That is solved by the RootPathProvider we find in the blogpost by Jef Claes. In VB.Net that would look like this.
```vbnet
Imports System.IO
Imports Nancy
Public Class RootPathProvider
Implements IRootPathProvider
Private Shared _cachedRootPath As String
Public Function GetRootPath() As String Implements IRootPathProvider.GetRootPath
If Not String.IsNullOrEmpty(_cachedRootPath) Then Return _cachedRootPath
Dim currentDirectory = New DirectoryInfo(Environment.CurrentDirectory)
Dim rootPathFound = False
While Not rootPathFound
Dim directoriesContainingViewFolder = currentDirectory.GetDirectories("Views", SearchOption.AllDirectories)
If directoriesContainingViewFolder.Any() Then
_cachedRootPath = directoriesContainingViewFolder.First().FullName
rootPathFound = True
End If
currentDirectory = currentDirectory.Parent
End While
Return _cachedRootPath
End Function
Public Function Equals1(obj As Object) As Boolean Implements IHideObjectMembers.Equals
End Function
Public Function GetHashCode1() As Integer Implements IHideObjectMembers.GetHashCode
End Function
Public Function GetType1() As Type Implements IHideObjectMembers.GetType
End Function
Public Function ToString1() As String Implements IHideObjectMembers.ToString
End Function
End Class```
The above presumes your views are in a Views subfolder. Which they are of course.
And now we can start writing tests.
```vbnet
<Test>
Public Sub IfPlantsRouteReturnsStatusCodeOk()
Dim result = _browser.Get("/plants", Sub(x)
x.HttpRequest()
End Sub)
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode)
End Sub
<Test>
Public Sub IfPlantWithId1RouteReturnsStatusCodeOk()
Dim result = _browser.Get("/plants/1", Sub(x)
x.HttpRequest()
End Sub)
Assert.AreEqual(HttpStatusCode.OK, result.StatusCode)
End Sub
<Test>
Public Sub IfPlantWithIdabcRouteReturnsStatusCodeOk()
Dim result = _browser.Get("/plants/abc", Sub(x)
x.HttpRequest()
End Sub)
Assert.AreEqual(HttpStatusCode.NotFound, result.StatusCode)
End Sub```
I just want to check if I get an ok code when it works and a not found when I do plants/abc
But the last test fails. With this exception.
```vbnet
System.Exception : ConfigurableBootstrapper Exception
----> Nancy.RequestExecutionException : Oh noes!
----> System.InvalidCastException : Conversion from string "abc" to type 'Double' is not valid.
----> System.FormatException : Input string was not in a correct format.
Time to change our Module. And do the simplest thing to make our test pass.
```vbnet Imports WebApplication2.Model Imports Nancy
Public Class PlantsModule Inherits NancyModule
Public Sub New()
MyBase.Get("/plants") = Function(parameters)
Return View(New PlantsModel() With {.Plants = New List(Of PlantModel) From {New PlantModel() With {.Id = 2, .Name = "test"}}})
End Function
MyBase.Get("/plants/{Id}") = Function(parameters)
If Not IsNumeric(parameters.id) Then Return HttpStatusCode.NotFound
If parameters.id = 1 Then
Return View(New PlantModel() With {.Id = 1, .Name = "test"})
Else
Return View(New PlantModel() With {.Id = 2, .Name = "test"})
End If
End Function
End Sub
End Class``` And now all three of our tests pass.
Don’t worry I can write more tests.
Conclusion
I figured it out, so it isn’t that hard ;-).
Update
Since version 0.15 the viewengine also needs a textresource. So now the setup looks like this.
vbnet
<SetUp()>
Public Sub FixtureSetup()
Dim configuration = A.Fake(Of IRazorConfiguration)()
Dim textResource = A.Fake(Of ITextResource)()
Dim bootstrapper = New ConfigurableBootstrapper(Sub(config)
config.Module(Of PlantsModule)()
config.Dependency(Of ITextResource)(textResource)
config.ViewEngine(New RazorViewEngine(configuration, textResource))
End Sub)
_browser = New Browser(bootstrapper)
End Sub