In the previous Getting Started with Lucid series (see parts 1, 2 and 3), I gave a general idea of how to use the Lucid tool, with some broad brush strokes into the execution cycle as well as some of the options you can use to modify that cycle. Here we’ll investigate how to get Lucid to talk with another application that you want to test.
For this post, we’ll use a very simple web application. First, download the Triangle Web App file. This file contains a web page that can be served up by the Sinatra application. So you will need Sinatra for this.
$ gem install sinatra
The Triangle Web App is a simple, self-contained web application that will allow us to use a web-based triangle program for testing purposes. To run, it just do this:
$ ruby triangle_web_app.rb
That should fire up Sinatra. Now browse to http://localhost:4567. This is the simple application I’ll use throughout this post. Essentially all it asks you to do is enter in the sides of a triangle and then allows you to evaluate not just your current response but your overall set of responses.
Let’s first create a directory structure, similar to what was ultimately done in the Getting Started with Lucid posts. First create a project directory where you want to store everything. Then, within that directory, create a series of directories that will let you segregate your work:
$ mkdir specs $ mkdir common $ mkdir steps
If you read the Getting Started posts, you’ll know that this directory structure is not necessary. You could have just used one directory, called specs, and stored everything in there. You could also use any directory names you want and simply tell Lucid which directories to use. The above case is using directories that Lucid will look for by default.
Creating Your Test Spec and Test Steps
Create a file in your specs directory called triangle_app.spec. Put the following in place:
Feature: Triangle Web Tester As a business hiring testers We need an application that allows candidates to enter data conditions So that we can determine what kinds of tests the candidates think of It is important for the application to give correct responses in order for us to accurately evaluate what the candidate is entering in. Scenario: No Conditions Tried Given the triangle app When evaluating data conditions with no conditions being tried Then the tester should receive no score
You can actually skip all the narrative elements below the Feature and above the Scenario. I put that there just to remind that it generally is a good idea to put information about the test specification in place.
You can run Lucid at the command line to help you generate the matchers for the above test steps:
$ lucid
As a note: if you are using this spec file as part of the directory structure you created in the Getting Started posts, running the above command will run all spec files in your specs directory. If you just want to run this one spec, you can do this:
$ lucid specs/triangle_app.spec
Create a file in your steps directory called triangle_app_steps.rb. That file will have the following contents:
1 2 3 4 5 6 7 8 9 10 11 |
Given (/^the triangle app$/) do pending end When (/^evaluating data conditions with no conditions being tried$/) do pending end Then (/^the tester should receive no score$/) do pending end |
Driving the Browser
In the getting started series of posts, I had you basically testing a set of Ruby logic that we wrote on the fly. We simply had the test definitions make calls to that Ruby logic and that was how we determined if the tests were passing or not. In this case, however, we have a web application we have to go to.
Keep in mind that Lucid does not know how to talk to browsers and it certainly doesn’t know how to talk to a web application running within a browser. These are external systems that Lucid, by design, has no knowledge of. After all, how could it? So how do you test an external system, like a web application, with Lucid? Generally you’ll do this by delegating the work to libraries that have been constructed for just that very purpose. You then reference those libraries in your test definitions which will do the work of connecting to the system that you are testing.
In this case, I want to use Capybara as my browser driver. (I actually have a series of posts, using the Capybara tag that talk about the tool in much greater depth, so I will forgo that discussion here.) Make sure you have Capybara:
$ gem install capybara
If you don’t have selenium-webdriver, you will need that as well:
$ gem install selenium-webdriver
The first thing I need to do, in my Given test definition, is use Capybara to visit the web page in question. Change your test definition so that it looks like this:
1 2 3 |
Given (/^the triangle app$/) do visit('http://localhost:4567') end |
That is how Capybara will allow you to visit a particular URL. That said, I’ve already mentioned that Lucid has no idea how to talk with the browser or with Capybara. So how do I make that work? To get started on that, create a file called driver.rb in your common directory. In that file, put the following:
1 2 3 4 5 6 7 |
require 'capybara' require 'capybara/dsl' Capybara.run_server = false Capybara.current_driver = :selenium Domain(Capybara::DSL) |
Here what I’ve done is make sure that Lucid has a file in place that tells it what library to load up — in this case, Capybara — and then I’ve provided any configuration required. Here, for example, I’ve told Capybara not to start what’s called a Rack server by default. Further, I’ve told Capybara that it will be using Selenium as its driver.
Finally, since Capybara provides a DSL that can be used, I am making sure that this DSL is available to the domain that Lucid is establishing to run Capybara. I’ve done that using the Domain call, which is pretty much identical to the World call that exists in Cucumber.
Let’s make one change to the driver.rb file. Add the following to it:
1 2 3 4 5 |
... Capybara.run_server = false Capybara.current_driver = :selenium Capybara.app_host = 'http://localhost:4567' ... |
Why add that? Well, first change your Given test definition as follows:
1 2 3 |
Given (/^the triangle app$/) do visit('/') end |
The app_host setting means that now when you call visit(‘/’), Capybara will actually visit the URL that was provided as the app host. This saves you from having to duplicate the hostname throughout your test code.
Let’s finish out our test spec just so it can execute the scenario we have set up. Change your When and Then test definitions as such:
1 2 3 4 5 6 7 |
When (/^evaluating data conditions with no conditions being tried$/) do click_button 'Evaluate Data Conditions' end Then (/^the tester should receive no score$/) do page.should have_content("Your score is 0.") end |
Here I’m using elements provided by the Capybara DSL to take action on a button and to check if the page has certain content as a result of that action.
If you run the lucid command against this spec file, you should see it calls up your Firefox browser and loads up the application (from triangle_web_app.rb) and then executes the test against it.
The Driver File
What makes all this work — and what connects Lucid to Capybara — is the information we put in that driver.rb file. Lucid will automatically look for any file called driver.rb and execute it first before any other files, such as test definitions. The driver file can be anywhere that Lucid reads. Meaning, for example, I could have put the driver.rb file in the steps directory as opposed to the common directory. The file could also be nested within a series of directories.
If you want to see that Lucid is putting your driver file first, you can always check that with the following:
$ lucid --verbose
This driver file is very similar, at least in some ways, to what Cucumber often uses in the env.rb file.
You can also specify a different driver. Let’s say you really want to use Cucumber’s named file for what drives Lucid. In that case, you can tell Lucid that via the following:
$ lucid --driver-file env
This would tell Lucid to look for a driver file called env.rb rather than driver.rb.
You can have multiple driver.rb files in multiple directories. If that’s the case, each one of those will be treated as a driver file. So, for example, you might have one driver file that sets up Capybara. You may have another that sets up a JSON library so that you can do web service API testing. As long as each file is named driver.rb (or whatever you specified using the driver-file option), Lucid will recognize those as driver files and load them first.
The Domain
The idea of the Domain is that it’s a scoping mechanism that can be used to contain state that is shared between test definitions. This is very similar in operation to the World object that is created by Cucumber during its own execution cycle.
The idea is that before each scenario is executed, Lucid will create a new Domain. The test definitions for that scenario execute in the context of the Domain. This is, incidentally, why instance variables can be referenced between steps within a given scenario. Where this becomes powerful is that you can define your own logic in modules and then indicate to Lucid that these modules should be part of the Domain.
So with our example, we wanted to use the Capybara DSL which is defined in a module called DSL that is, in turn, defined within a module called Capybara. (If curious, you can check out Capybara’s dsl.rb file.) In order to be able to use this with the test definitions, we mixed in that module provided by Capybara with telling Lucid it is exists as part of the “domain of execution.”
The goal in this post was to show you how to connect up an external library, in this case a browser execution library, with Lucid. There are many other testing solutions out there and future posts will cover some of those, including one of my own called Fluent, which Lucid will generate projects for automatically.