Using canopy and F# for functional testing
There are a lot of ways to test the software. The most popular are for sure unit tests, but they check only separate part of the solution. Functional tests on the other hand, allows us to check whole application in testing environment – interaction to db, backend code, frontend code, browser compatibility. This is the thing that we do every time manually after adding new feature – we open browser and we do manual steps to check if everything is ok. By automating this we can save ourselves a lot of time.
In Java world the most popular tool for functional testing is Selenium, which was also adopted for .Net world and you can use it in your program. But in my opinion the easiest for functional testing in .Net is canopy which connects power of F# with power of Selenium.
The best example of what canopy is can be found on their homepage:
//these are similar to C# using statements open canopy open runner open System //start an instance of the firefox browser start firefox //this is how you define a test "taking canopy for a spin" &&& fun _ -> //this is an F# function body, it's whitespace enforced //go to url url "http://lefthandedgoat.github.io/canopy/testpages/" //assert that the element with an id of 'welcome' has //the text 'Welcome' "#welcome" == "Welcome" //assert that the element with an id of 'firstName' has the value 'John' "#firstName" == "John" //change the value of element with //an id of 'firstName' to 'Something Else' "#firstName" << "Something Else" //verify another element's value, click a button, //verify the element is updated "#button_clicked" == "button not clicked" click "#button" "#button_clicked" == "button clicked" //run all tests run() printfn "press [enter] to exit" System.Console.ReadLine() |> ignore quit()
This example is I believe self explenatory. By writing start firefox we start browser, then using url command we go page we want to test. We find html controls on page using standard “#by_id”, “.by_class” syntax and either by “==” we assert that value is correct or we use “<<“ to pass new value to control. To interact with page we have also very simple commands click “#button_id” or press enter. As you can see writing test in canopy looks pretty much as writing test in natural language, which I think is a great advantage of this framework.
To show you a little bit more complex example, I wanted to present you simple authentication tests. The first module – User:
module User open canopy open lib12.Data.Random open Consts let login user password = url LandingPageAddress click "#loginLink" on LoginPageAddress "#tEmail" << user "#tPassword" << password press enter on LoggedInLandingPage let logout = click "#logoutLink" on LandingPageAddress let registerRandomUser = url LandingPageAddress click "#registerLink" on RegisterPageAddress "#tEmail" << Rand.NextEmail() "#tPassword" << TestPassword "#tConfirmPassword" << TestPassword check "#chTermsAccepted" press enter on LoggedInLandingPage
LandingPageAddress, LoggedInLandingPage and others are part of Consts module. I create three reusable functions – login, logout and registerRandomUser. Login gets user and password as arguments and tries to pass them to login form after that checks if user is on correct landing page. Logout only job is to click logout link and check if user is on main page. Finally registerRandomUser uses my lib12 library to create random email address, pass it to registration form and check if user is logged in.
Actual test scenarios are created in Program module, when I create two simple scenarios to check login and user registration:
open canopy open runner open User open Consts start firefox "login and logout as test user" &&& fun _ -> login TestUser TestPassword logout "register new user and logout" &&& fun _ -> registerRandomUser logout run() printfn "press [enter] to exit" System.Console.ReadLine() |> ignore quit()
As you can see canopy is really easy, even for someone who doesn’t have a deep knowledge of F# and can be really useful for automation of web page testing.