Saturday, May 25, 2013

Case class enumeration in Play 2.1 Application (on top of Salat/MongoDB)

Recently in our Play 2.1(Scala) application I needed to implement a model that's like Java enum. Since scala's Enumeration class doesn't have a fantastic reputation, I decided to go with the case class approach. Our Play 2.1 application is a JSON REST API that sits on top of MongoDB, so I need to make sure that this model can have both JSON and MongoDBObject serialization wired up.
Let's start from Enum base trait
trait Enum[A] {
  trait Value { self: A => }
  val values: List[A]
  def parse(v: String) : Option[A] = values.find(_.toString() == v)
}
We'll see the use of the parse function later.

In our system we have a flag system for content entries. Here is the flag case class enum.
import com.novus.salat.annotations._

@Salat
sealed trait Flag extends Flag.Value

case object DEPRESSING extends Flag
case object VIOLENCE extends Flag
case object NSFW extends Flag

object Flag extends Enum[Flag] with SimpleEnumJson[Flag] {
  val values = List(DEPRESSING, VIOLENCE, NSFW)
}
The @Salat is needed for salat to map abstract class inheritance tree. SimpleEnumJson[T] is the one that provides Play 2.1 JSON API formats which you will need for JSON serialization. Here is its implementation.
import play.api.libs.json._

trait SimpleEnumJson[A] {
  self: Enum[A] =>

  implicit def reads: Reads[A] = new Reads[A] {
    def reads(json: JsValue): JsResult[A] = json match {
      case JsString(v) => parse(v) match {
        case Some(a) => JsSuccess(a)
        case _ => JsError(s"String value ($v) is not a valid enum item ")
      }
      case _ => JsError("String value expected")
    }
  }

  implicit def writes[A]: Writes[A] = new Writes[A] {
    def writes(v: A): JsValue = JsString(v.toString)
  }
}
As the name suggests, SimpleEnumJson uses the simple toString() of the enum item for JSON representation.
Note that we could place the items definitions inside the companion object, but unfortunately salat couldn't map the class that way.
This should be good enough for most cases, a simple case class based enum that can be used in any models.
Now let's make it a little more complex, let's say we need one more attribute in our Flag class: age rating - each flag indicates that the content is only appropriate for users above a certain age.
@Salat
sealed trait Flag extends Flag.Value {
  val ageRating : Int
}
case object DEPRESSING extends Flag { val ageRating = 18 }
case object VIOLENCE extends Flag { val ageRating = 16 }
case object NSFW extends Flag { val ageRating = 21 }
Now we need a bit more work for our JSON reads/writes, the SimpleEnumJSON[T] is no longer sufficient. Let's write a CompositeEnumJSON[T]
trait CompositeEnumJson[A] {
  self: Enum[A] =>
  implicit val reads = (__ \ 'name).read[String].map( parse(_).get )
  val nameWrite = (__ \ 'name).write[String]
  implicit val writes : OWrites[A]
}
Here we map a composite case class enum into a JsObject with a name field that holds the toString() value of the item. When we read from JSON, we only need the "name" field. We need concrete inheriting case class to implement the Json write:
object Flag extends Enum[Flag] with CompositeEnumJson[Flag] {
  val values = List(DEPRESSING, VIOLENCE, NSFW)
  implicit val writes : OWrites[Flag] = (
    nameWrite ~
    (__ \ 'ageRating).write[Int]
  )(unlift(unapply))

  def unapply(flag: Flag) = {
    Some(( flag.toString(), flag.ageRating ))
  }
}
There you have it - a composite case class based enum that can have attributes.
I hope you find this helpful and let me know if you have any suggestion for improvements.

Tuesday, May 07, 2013

Define arbitrary tasks in the Play 2.1 Framework (Rakes like)

Recently with the help from James Roper from Typesafe, I added some arbitrary tasks to our application so that we can seed some data from command line. These tasks are basically like rake tasks in which you can run fire up the application environment and perform code written for you application.

The idea is to create SBT tasks and then, quoted from James, "get a hold of the dependencies, create a new URLClassLoader with them, load the class you want to use from that classloader using reflection, and then invoke it."

Here is the code in the SBT build file Build.scala
import java.net.URLClassLoader
object ApplicationBuild extends Build {
//Other project settings such as appVersion and appDependencies

def registerTask(name: String, taskClass: String, description: String) = {
  val sbtTask = (dependencyClasspath in Runtime) map { (deps) =>
    val depURLs = deps.map(_.data.toURI.toURL).toArray
    val classLoader = new URLClassLoader(depURLs, null)
    val task = classLoader.
                 loadClass(taskClass).
                 newInstance().
                 asInstanceOf[Runnable]
    task.run()
  }
  TaskKey[Unit](name, description) <<= sbtTask.dependsOn(compile in Compile)
}

val main = play.Project(appName, appVersion, appDependencies).settings(
  registerTask("seed-data-book","tasks.SeedBooks", "seed for book table" ),
  registerTask("seed-data-user","tasks.SeedUsers", "seed for user table" )
)

Here is our task classes (I placed it in app/tasks)
package tasks
abstract Task extends Runnable { 
  val application = new StaticApplication(new java.io.File("."))
}
    
class SeedBooks extends Task{
  def run {
    Book.dao.save(new Book("Introduction to Scala", "Martin Odersky"))
  }
}
    
class SeedUsers extends Task{
  def run {
    User.dao.save(new User("jRoper", "password"))
  }
}
I hope this helps. Feel free to ask any questions in the comments.

Sunday, February 24, 2013

Server-side view or client-side MV*?

Recently I came across a video in which David Heinemeier Hansson(a.k.a DHH, creator of Rails) talked about client-side MVC vs the traditional Rails way of developing web applications. In the video DHH claimed that the development experience of client-side MVC is inferior compared to traditional Rails development. He didn't give a lot more specific reasoning except:
  1. you can't write ruby at client-side.
  2. client-side MVC is "extra complexity" that is not worth the effort most of the time.
Personally I like CoffeeScript better, especially on the functional programming side, but I am not going to argue about it in this article. This article is about why the second reason he gave is wrong.
I'll first show some code comparison between the two paradigms to demonstrate the software design drive for client-side MV* and then I will talk about the business drive for client-side MVC(*) - interactivity.

Is it more complexity or more elegance?

DHH claimed that client-side MVC is more complex compared to server-side views, but is it? Or is it just more elegant? Let's look at some code. How about we write a simple todo list in both client-side MVC and traditional Rails way.
Rails way
erb view:
<ul>
  <% @todos.each do |todo| %>
    <li> <%= todo.title %> </li>
  <% end %>
</ul>
controller:
class TodosController < ApplicationController
  def index 
    @todos = Todo.all
  end
end  

Client-side MVC
service controller:
class TodosController < ApplicationController
  def index 
    render json: Todo.all
  end
end  
HTML view:
<ul>
  <li> {{title}} </li>
</ul>
client-side MVC coffeescript:
$ ->
  todos = new Collection(url: '/todos')
  new CollectionView(collection: todos, el: $('ul')) 
  todos.fetch()
  #The Collection and CollectionView is not standard Backbone class. We extended it a little bit in our internal Backbone library. 

The client-side MVC version does need some client-side MVC code, but whether it's resentful complexity or elegance with clearer view logic is arguable. Now let's add a dropdown filter so that user can filter the list by todos' status: 'completed' and 'overdue'.
Rails way
erb view:
<%= form_tag("/todos", :method => "get") do %>
  <%= select_field_tag('filter', 
     options_for_select(['completed','overdue'], @filter)) %>
<% end %>
You also need a little bit help from the client-side so that user doesn't need to click a submit button to submit the form.
$ -> $('select').on 'change', $('form').submit
Controller:
class TodosController < ApplicationController
  def index 
    @filter = params[:filter]
    @todos = @filter.present? ? Todo.where(status: @filter) :
                                Todo.all
  end
end  
Client-side MVC
HTML view
<select name='filter'>
  <option>completed</option>
  <option>overdue</option>
</select>
A new view is needed at the client-side MVC:
class FilterView extends Backbone.View
  events: 'change' : 'refresh'
  refresh: => @collection.fetch data: { filter: @$el.val()}
Add this view to the page load initialization
$ ->
  ...other initializations mentioned above...  
  new FilterView(collection: todos, el: $('select')) 
Controller:
class TodosController < ApplicationController
  def index 
    @todos = params[:filter] ? Todo.where(status: params[:filter]) :
                               Todo.all
  end
end  
This time the effort required in the client-side MVC solution is arguably at the same level. You need to write a new view class and initialize it but in exchange your HTML view is much cleaner than the erb template. The extra CoffeeScript in the Rails solution perfectly exposed its inelegance - why do you need a HTML form? Also, you might notice that the server-side controller is slightly cleaner when it doesn't have to remember the filter state at the client-side (I know you can access params directly from the view but that's frowned upon).

From a software design/architecture point of view, where to place the view logic is not a very tricky question. We don't need philosophical debate to sort it out. View logic needs both to access server-side data and to interact with client-side HTML DOM. Clearly it's more convenient/efficient/logical to place view logic close to where it has the most interaction. In the old days, the only user interaction is simple back and forth HTML form request and HTML page response, the view logic relied mostly on the server-side data. Nowadays web app UI has become a lot more dynamic and complex, there is way more dependency towards client-side DOM and states then server-side data. That's why placing view logic at the client-side is more efficient at this age.

It's the interactivity, stupid.

DHH admitted that certain level of user interactivity justifies such 'extra' effort for client MV*. He was close but did not get to the point. Interactivity is the essential for better UX. When your page is simple, yes, you don't need that much interactivity. But the market will demand more and more functionality on that page. The only way to keep the UX clean and intuitive is through creative interactivity.
DHH told the story that he chose Backbone to do a calendar because it's a highly interactive component and he used traditional server-side view for other "information" page. This hybrid approach is not that bad an idea when you can foresee how interactive each part of your app is. What DHH failed to see is that it is not the case for a website reasonably ambitious to be modern.

A good example is the todo list mentioned In DHH's story about his development of Basecame Next. He couldn't decide which way to go, client-side mvc or the Rails way. He couldn't tell if the amount of the interactivity in a todo list demands client-side MVC. So he wrote both a rails+ad-hoc javascript version and a Backbone version. He ended up with the rails+ad-hoc javascript version because it's less code and more 'elegant' and can also serve the interactivity needed for that todo list. But what if the market one day says we want more functionality in that todo list? The ad-hoc javascript and view logic in rails would become more and more messy until it would have to be rewritten in client-side MVC.

Actually, all the "information" pages he mentioned could be designed differently with more interactivity if the developer was not in the traditional Rails html form and view mindset. For example, in the comments page, how about we allow user to reply to any comment? The user clicks the reply button, a text input shows up below, the user types in the reply and it gets attached right after the original comment? True this maybe achieved by refreshing the whole comments container but what if he is also in the middle of replying to another comment? What if we want that new reply to show up in some sort of animation? (If you ask why animation, I suggest some with how animation can provide visual feedback and enhance UX)?

Embrace a new paradigm not because it's "shiny", but because it can free us from our old mindsets

One of the DHH's frustrations over the current client-side MVC trend was that he thought other people are adopting this new paradigm simply because it's new. I have to say that he misunderstood them. It's the trend not because it looks new, nor is it only because it naturally provides fluent UX. It is because it opens our eyes to rethink HTML and explore the many new possibilities on how to design a better web application (interactivity is one of the keys).

DHH showed us an good example of such confinements from one's old mindset when he talked about how awesome the form_for helper is. HTML form is simply a broken piece of HTML, it made user interaction rigid and boring and it couldn't even do the HTTP method correctly. And the form_for helper was partly to help server side keep client side state (so that a form submitted can be rendered again the way it is submitted, e.g. when server side validation failed), which shows how unnatural the server side view is - letting stateless server side maintain the state at the client side.

When World Wide Web started, the interaction between client and server was designed to be get/form request and HTML response. It worked fine for over a decade, but we have started (for years) the transition to a new highly interactive WWW. Views logic resides at the client-side powered by much stronger JS engine and communication between client and server is cut down to it's bare bones - simple json data. Both make perfect philosophical and practical sense. If our client-side MVC framework isn't perfect and introduces boilerplates, then we should improve it. What we should not do is to insist on keeping view logic at the server-side simply because we have been doing that for decades.

Wednesday, January 30, 2013

Still not convinced about coffeescript?

Here is another example why you should start writing Coffeescript. The business story in this example is rather simple - I need to load all document from a collection (named Accounts), perform an asynchronous operation (notifyOwner) on each of them, and save all of them back to DB after all notifyOwner operations finish successfully. The following methods are available to achieve this simple task:
Account.find() #find all accounts
account.notifyOwner() 
account.save()
All three methods are asynchronous and return a jQuery promise which resolve with either the results or itself for chaining. Because there are multiple accounts involved, we will also need to take advantage of jQuery.when.

Here is how we implement the business logic in Coffeescript

Account.find()
  .then (accounts)->
     $.when (account.notifyOwner() for account in accounts)...
  .then (accounts...)->
     $.when (account.save() for account in accounts)...
  .done ->
     console.log 'successfully notified all owners'
It takes advantage of coffeescript's splats feature to overcome jQuery.when's inability to take in an array of deferred.
  #resolves only when all three deferred resolve) 
  jQuery.when(deferred1, deferred2. deferred3) 
  
  #immediately resolves with the array passed in) 
  jQuery.when([deferred1, deferred2. deferred3]) 
What Javascript does that Coffeescript translate to?
Account.find().then(function(accounts) {
  var account;
  return $.when.apply($, (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = accounts.length; _i < _len; _i++) {
      account = accounts[_i];
      _results.push(account.notifyOwner());
    }
    return _results;
  })());
}).then(function() {
  var account, accounts;
  accounts = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
  return $.when.apply($, (function() {
    var _i, _len, _results;
    _results = [];
    for (_i = 0, _len = accounts.length; _i < _len; _i++) {
      account = accounts[_i];
      _results.push(account.save());
    }
    return _results;
  })());
}).done(function() {
  return console.log('successfully notified all owners');
});
If you don't mind a bit help from underscore, We probably can simplify the iteration logic:
Account.find().then(function(accounts) {
  var account;
  return $.when.apply($, (function() {
    return _(accounts).map(function(account){
      return account.notifyOwner();
    });
  })());
}).then(function() {
  var accounts = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
  return $.when.apply($, (function() {
    return _(accounts).map(function(account){
      return account.save();
    });
  })());
}).done(function() {
  return console.log('successfully notified all owners');
});
So, that's clearly a lot more key strokes than Coffeescript but that's not the point. The point is how easy to read this Javascript version vs the Coffeescript version. Code could be written only once but it often times has to be read multiple times afterwards. Which version will you rather read?

Now, are you convinced?

Monday, May 07, 2012

Full stack functional testing for hackers

Why do I care about full stack functional testing?

Because you really care about the quality of your product but you also care about the cost of QA. The most cost efficient option is probably full stack functional testing, which isn't exactly easy, but hey, you are a hacker, aren't you?

For the sake of conciseness, "full stack functional testing" will be mostly referred as "functional testing" in the remainder of this article.

Why unit tests, no matter how good they are, can't replace real QA?

There are many reasons, here are several examples:
  • It's common that when writing unit tests, developers use mocks to isolate the modules they are testing against and leave the integration points between modules untested. It is perfectly normal that you can have 100% unit tests coverage and your application is still completely broken.
  • Unit tests, by its nature, do not cover integration points with external modules/APIs and thus do not protect your application from the behavior changes from them when you upgrade them. Traditionally developers are cautious about upgrading external libraries because often times it will trigger the need for a full regression tests.
  • The logic unit tests are testing is sometimes too far away from the behavior logic end user is interacting with.
  • Unit tests do not provide enough confidence during major refactoring especially when a significant number of unit tests themselves need to be changed due to the refactoring.
  • For web applications, unit tests do not test cross browser compatibility.
In one sentence, you can't be serious if you plan to live without QA because "my application is pretty well covered by unit tests."

Why full-stack functional tests? Does it count to have functional tests against a lower layer, e.g. the web service layer?

Modern web applications have lots of UI logic happening in the browser (written in JS) and the integration between the UI and backend web service is too complex not to test. The point of full-stack functional tests testing from UI layer all the way to the persistence layer is that they perform the same interaction against the application exactly like real users (just faster). When they pass, you have 100% confidence your application works. Leaving out any layers will cost you that ultimate purpose.

Why functional tests are cheaper than manual QA?

You are a hacker, you know the motto: automation, automation, automation. Automated regression tests is by several magnitudes faster than manual regression tests. Actually, since the scope of regression tests will keep increasing along with the growth of the application, the time manual regression tests take will soon start to hurt the application's time to market. So, if you care about both quality and time to market, automated functional tests is the only salable way to do regression tests.

Why full stack functional tests are often claimed to be too fragile to worth it?

Functional testing is significantly different from unit testing which developers are more used to. The main factor that makes functional testing harder is the amount of uncertainties in functional testing:
  • The simple fact that they test end to end means that there are a lot more internal and external factors can impact functional tests.
  • It's harder for your to always test on a clean set of data - the amount of data needed for each functional test forbid you from setting up data on every test.
  • UI interaction is asynchronous and the response time isn't exactly deterministic. Tests could fail randomly when the assertion is made too early, or, put in another way, the expected results show up too late.
Thus debugging functional tests is more challenging than debugging the more deterministic unit test. It is very common that functional suites start fragile and take time to improve gradually until its robustness and stability reach a satisfactory level. Yes, there is a learning curve for developers how are used to writing unit tests, but it's not a "forget it, it's not worth it" one. All you need is the right developers.

How to improve the stability of functional tests over time?

When a test fails due to the undeterministic nature of functional tests, instead of running it again and stops when the test passes, take the time to improve the stability. A very important tool to have here is the ability to automatically do screen captures when a functional test fails because you might not be able to repeat it easily.

Sometimes it takes some guessing to figure out what happened, but most of such "random" failings are caused by the fact that the responsiveness of UI isn't deterministic. To give a more specific example, suppose your test clicks a button on the UI and assert that some expected result. It could fail randomly when your assertion is made "faster" than the response. A common technique is to poll UI with certain frequency for a period of time, during which the test keeps reading the UI for some indication that the application has fully responded. Then the test can assert the expected result. This polling ability is a must for your functional test framework.

Why is it the developers' responsibility to write functional tests?

There are at least 3 reasons:
  • Only developers can make sure the UI is automatically testable and easily update functional tests according to UI change.
  • Functional tests are code, lots of them. Writing readable functional tests requires at least basic OO design skills.
  • Improving the stability of functional tests is a tough job that requires virtuosity in debugging, patience and the confidence to overcome technical challenges. Most people with such capabilities tend to developers, usually pretty good ones.

What does it take to successfully write and maintain functional tests?

As mentioned above, the biggest challenge in functional testing is the debugging bugs that appear to be random. Virtuosity in debugging, patience and confidence in tackling technical challenges are what you should look for when finding developers that can successively execute the use-functional-tests-for-QA strategy. They usually go together. If a developer easily gets frustrated or even annoyed by the undeterministic nature of functional tests, s/he won't be able to effectively debug it and improve the robustness of it, and in turn to make herself to believe that functional testing is always going to be fragile and thus won't work.

If functional tests cover everything, do I still write unit tests?

The purpose of functional tests and unit tests in TDD is very different. Functional tests are mainly for code coverage to ensure functionality. In TDD, the main purpose of unit tests is to drive development, and the code coverage provided is more like a side effect. Thus functional tests cannot replace unit tests for that purpose. That being said, the code coverage provided by functional tests can help TDD because developers can now focus more on the drive-development purpose when writing unit tests without having to also keep code coverage in mind. Arguably, with functional tests you can chose other development methodologies without much immediate risk introduced to the quality of the software. So it opens up more options for the developers.

If the developers are writing functional tests that covers everything, do I still need dedicated QAs?

You will have more edge case issues experienced by your end users without dedicated QAs or dedicated QA process. Developers are not trained, or interested, in testing the system against all special cases. Edge case issues will be discovered and fixed more in an on demand fashion. A good strategy would be to automatically monitor your application closely and alarm your developers (and/or automatically rollback changes) whenever any abnormal things happen, such as exceptions, sudden user activity changes and so on. Then your developers can fix them a.s.a.p and add functional tests accordingly. This approach is arguably more agile because you don't spend the cost in front to fix some edge issues that may never be met by the real end users.

What tools are needed for writing functional tests for a web application?

Just a couple:
  • Selenium - selenium 2.0 (webdriver) is much better and quite stable, although the documentation isn't that great (here are some tips)
  • Chromedriver - faster than Firefox, but has some limitation comparing to Firefox whose selenium driver is the most mature one.
  • Your favorite BDD framework.
Given that the problem functional testing is trying to solve is already complex enough, it would be wise to keep the technology stack as simple as possible. The need for any extra layers on top of Selenium or BDD is very limited. You might need to write some simple helper methods to hide some boilerplate code needed for selenium, but not much more.

Why BDD framework over Unit Testing framework when it comes to functional tests?

Although using unit test structures to organize functional tests should work, it is more natural to organize functional tests into contexts and scenarios, which BDD frameworks usually support better.

Is there any good pattern in writing functional tests?

The basic idea is to first model the application UI you are testing against and then write tests against that model. A popular pattern based on this idea is called page object pattern. In this pattern, you write classes to represent UI pages so that
  • Detailed UI interaction implementation is hidden in these classes, e.g. the logic of how to locate a button.
  • Only business meaningful methods are exposed, e.g. submit_order or set_shipping_address
For a simplified ruby example, here is a page object for a checkout page
  class CheckoutPage
    def set_shipping_address(address)
      browser.find_element("input#street").send_keys(address[:street])
      browser.find_element("input#city").send_keys(address[:city])
    end

    def use_shipping_as_billing=(same)
      checkbox = browser.find_element("#same-shipping-billing")
      checkbox.click if checkbox.selected != same
    end

    def submit_order
      browser.find_element("input[type='submit']").click
    end
  end
Then you can write tests like
  checkout_page = CheckoutPage.new
  checkout_page.set_shipping_address(street: "20 Jane St", city: "London")
  checkout_page.set_credit_card_info(cc_num: "12345678", exp: "6/12")
  checkout_page.use_shipping_as_billing = true
  thank_you_page = checkout_page.submit_order
  thank_you_page.thank_you_message.should be_displayed
As you can see, by separating the modeling of the application from the tests, you can have much better readable tests as well as reusable UI manipulation code.

Of course, you don't have to stop at the page level, you can also create partial(or control) objects to model a smaller part of the page. In one sentence, use your OO skill to model the pages/ui components in the most sensible way.

Is it possible to let the business people read or even write functional tests?

No. That's not going to work and don't waist your time or money on that. The goal for functional testing is to QA the product, it'll be wise not to get distracted by adding more responsibilities for functional testing.



Any comments are welcome. updated with one more Q&A about why only full-stack functional testing has to include every layer.

Thursday, May 03, 2012

Some selenium tips

UPDATES
  • May 31, 2012: Added the tip to capture the screen when test fails.
  • May 11, 2012: Added the tip that about keeping the browser window displaying (or hidden) during the tests.
  • May 11, 2012: Rephrase the scroll to a button before clicking it tip.

Watch out the outdated articles on the internet.

Selenium 2.0 is completely different from Selenium 1.x. Selenium 2.0 is also called the selenium webdriver. So always add the keyword webdriver when googling for answers to your selenium related questions.

Implement the web UI in a modular way so it's more selenium testable.

Modularize your view logic so that you only update the part of DOM that is needed to change when your models change. If you tend to re-create a bigger part of the DOM than necessary, it's not only a waste but also could introduce risk to your functional tests written in Selenium.

Reduce unnecessary dependency on DOM structure, make element locating logic as simple as possible.

When you need to locate an element, try not rely on the DOM structure too much - for example, using code logic to locate element is the most risky one. The best approach is probably to always use a scoped CSS selector with 1 or 2 levels of IDs, And if you can locate it in one selector, don't do it in two. For example
  label = driver.find_element("#info-panel #name-label")
is more robust than
  panel = driver.find_element("#info-panel")
  label = panel.find_element("#name-label")

Do waiting in selenium the smart way.

Don't use implicit wait blindly. Implicit wait makes sense when you use find_element to find one element. But when you try to locate multiple elements by driver.find_elements, the driver will always wait the whole timeout period if implicit wait is set. That might not be what you always want. I usually write my own safe find_element method. Here is an example in the base class of my page objects:
    def s selector
      wait_until { @driver.find_element css: selector }
    end

    def wait_until(&block)
      wait = Selenium::WebDriver::Wait.new(timeout: 10, interval: INTERVAL)
      wait.until &block
    end
So that I can write the following code in my page object
   def submit_order
     s('button#submit').click
   end
The short method name "s" is inspired by jQuery. Here it will keep polling the DOM for 10 seconds until it finds the button with id "submit". It's like implicit wait but only for finding one element. When you really need to wait for multiple elements, you can use an explicit wait, which, to me, makes more sense than a hidden implicit one.

Set the initial browser window size when using Chromedriver.

Ruby code:
  profile = Selenium::WebDriver::Chrome::Profile.new
  profile['browser.window_placement.top'] = 0
  profile['browser.window_placement.left'] = 0
  profile['browser.window_placement.right'] = 1024
  profile['browser.window_placement.bottom'] = 768
  driver = Selenium::WebDriver.for :chrome, profile: profile
This works in both Windows and OSX (will try Linux and update here)
Bad news for Java, C# and Python coders though, it seems that as of now setting chrome preference is not supported in the java version of Webdrive. Your best chance could be creating a ChromeProfile class based on the exiting FirefoxProfile class.

Scroll to a button before clicking it.

Clicking buttons sometimes randomly fail. It could be caused by the fact that the button has to be the view area to be clickable and somehow the selenium auto scroll failed. In this case, add a scroll to button will improve the robustness of your suite.

When running the test using Firefox, it matters whether the browser window is displayed on the screen or hidden behind other windows.

From my experience, my guess is that selenium interacts with the browser in slightly different ways depending on if the browser is displaying in the front or not. There is rare case that certain selenium operations only work when the Firefox is displaying in the front. When running the selenium suite, changing the z position of the browser window (and thus either show or hide the browser window from other applications) can affect the tests. So you get more consistent results by keeping the browser either showing in the front(or hidden in the back) during the course of full suite.

Capture screenshots when test fails (RSpec)

In your spec_helper.rb
  RSpec.configure do |config|
    config.after(:each) do
      capture_screen_when_fails(example, @page) 
    end

    def capture_screen_when_fails example, page
      if(example.exception.present? and page.present?)
        page.capture_screen(example.description) 
      end
    end
  end
Note here that you need to keep your page object instance in an instance variable(in my case @page) in your spec. I used a naive way to name the screenshot after the example's description.
Now in your base class for your page object.
    def capture_screen filename
      path = "PATH_TO_TMP/#{filename}.png"
      @driver.save_screenshot(path) 
    end
Note that @driver is the instance variable holding the selenium webdriver currently running.

Thursday, December 08, 2011

Test first != TDD

Recently I've seen a misunderstanding of TDD(test driven development), that is, if you always write test first and write code that passes that test, and voilĂ , you are TDDing, everything will be better now. That is not TDD. That is 100%-test-coverage-driven-development.

TDD is NOT about achieving 100% test coverage (which IMO is meaningless).

TDD is about using test to drive development.

More specifically, TDD requires three equally important types of activities:
  • writing test
  • writing the simplest code that passes the test
  • refactoring code that keeps tests passing
A common misunderstanding is that the refactoring step is optional. It's not. The following is not TDD.
First the test:
   describe 'alert' do
      it 'should log the message' do 
         logger.should_receive(:info).with('a message');
         subject.alert('a message');
      end
   end
Then the method in tested class:
    def alert(msg)
       logger.info(msg)
    end
Then you are done with this method. This is NOT TDD.
First, you didn't refactor the code. Second, it's not likely that the test will help when you need to refactor this code in the future. In one sentence, the refactor-and-keep-tests-green part is missing.
So what will a TDDer do here? Simply write the code without the test. A typical argument against it is that what if some other developer accidentally delete the logger.info(msg) code? Well, that's not the purpose of TDD, that is what version control is for.

In fact, it can be argued that this test is a form of code duplication. It's just that this duplication is very easy to detect (if you change one place without the other, the test will break.)
Things could be a bit different if your code is like this.
   describe 'alert' do
      it 'should log the title and message' do 
         logger.should_receive(:info).with('a title: a message');
         subject.alert('a title', 'a message');
      end
   end

   def alert(title, msg)
      logger.info(title + ': ' + msg)
   end
There is a possibility that you need to refactor to improve the performance of the string concatenation. In this case, the test here has some value.

So, the purpose of tests in TDD is to facilitate refactoring.

In many cases, tests give you the ability to refactor code with the confidence that it won't break functionality. In other cases, you may have to change some tests to do your refactoring, because unless it's a real black box end to end test, you are always going to have some form of logic duplication in your tests.
So a test is probably helpful for some refactoring but impeding for some other refactoring.

The value of a test is determined by the likelihood of it helping refactoring v.s. the likelihood of it impeding it.

When writing tests in TDD, we need to maximize this value with as less cost as possible. Tests on constructors, accessors, constants and simply delegations are typical examples of test with zero or negative value. Pure interaction tests are likely to have less value than a more end-to-end test but it should be evaluated on case-by-case basis.
You also need to take cost into consideration - for example, end-to-end test might takes more effort to write and/or more resource to run.
There is no silver bullet. Always-write-test-first isn't one. It takes some effort to determine when to write tests and how to do so, but it's not too hard - just focus on the value of the test, that is, how much benefits it can bring to immediate and foreseeable refactoring.

Update on Feb 11, 2012

I got the chance to discuss with Martin Fowler about this topic last night. The conversation started when I said "some people think TDD is all about write test first and implement it then done." Martin immediately replied "no, no, no, always refactor later. It should always be red, green, green." Then he quickly reaffirmed my understanding of TDD addressed above:
1, Achieving 100% of test coverage is NEVER the goal of TDD. A sound value of test coverage in TDD should be in the 90's.
2, Tests are for the sake of refactoring. They are written for testing "interesting" stuff. He would not test simple delegation (like the example given above) . Testing a simple delegation using mock has no value since it does not provide any benefits to future refactoring.
He also preferred test at a higher level which I couldn't agree with more. Recently I found that the higher level your tests are the more value they provides. Lower level unit tests are cheaper, but you need to keep in mind the value they can bring. Again, tests are for the purpose of confirming that some "interesting stuff" works, not that some code were written.