views:

553

answers:

4

I am trying to write some cucumber tests for my application that uses Authlogic for authentication, but actually stores users in a LDAP server.

The application seems to work fine, but where I am running into trouble is writing tests for it (I know, I know, I should've wrote the tests first.) It's easy to have a test database where the data is cleared out after each run, but not so easy with an LDAP server.

My idea was to write a rake task (like rake ldap:test:prepare) to refresh the ldap server before each run (or make it a dependency), but that seems pretty time consuming when I am working on tests (and makes autotest near impossible.)

Is there a better way to do this? Is there a ruby-based fake LDAP server I can bind to with pre-defined fixtures? Is there some other even more elegant solution that I am not thinking of? (not using LDAP isn't an option.)

A: 

Hi Dan,

Not really an answer but...I'm working on a very similar problem, testing LDAP authentication and lookup code with cucumber. Have you looked into using a stub in your test? I was thinking of stubbing my LDAP responses...just haven't figured out how to do it yet.

Matt

Matt
I am late to the testing game (the upgrade to 2.3.4 broke one of my applications, so I decided it was time to start writing some tests..) so I am not very well versed in all the techniques that people use (eg. I've heard the term stub, but that's about as far as my knowledge goes), so I was thinking there was an easy and acceptable best practice that I just didn't know about rather than some complicated test LDAP server solution. But, no one yet has answered, so maybe there's not!
Dan McNevin
+1  A: 

So in general Cucumber tests are for integration and acceptance testing. That being the case it is supposed to test the system end-to-end, so it should be testing the LDAP integration as well. My suggestion, if you can swing it, would be to set up another LDAP server and do a periodic dump from your live one to set it up with whatever test data you need.

I will say though that your first idea of having the dependency that refreshes the LDAP db before each run is the "right" way to do it. Integration/acceptance testing is supposed to take a long time. It is testing the entirety of the functionality of the system, not just small (unit) pieces.

Cucumber is not a unit testing framework, and shouldn't be used in that manner. If your application broke after migrating to 2.3.4 because you didn't have tests I think you should get in there and start writing some unit tests...

Now this is my personal bias, but if you have no unit tests in place I would take a look at RSpec. If you like the english-like syntax of Cucumber, RSpec will definitely feel similar. If you are already somewhat tested in Test::Unit, I would definitely suggest bringing Shoulda to the party or possibly Context/Matchy (all of which are available on github) to get the RSpec feel within the Test::Unit framework.

Shane Liebling
Seems reasonable. I was sort of hoping there would be some magical gem that would mock a LDAP sever that I couldn't find on github, rubyforge, or google so I didn't actually have to do the work.I am trying to work through all of the testing options available to Rails and feeling kind of overwhelmed by all the choices and strong opinions out there. I do like your explanation of the different roles of the different testing frameworks, though, so I am going to accept this answer. Thanks!
Dan McNevin
+1  A: 

I was finally able to get around to basically cleaning the ldap server before each cucumber scenario was run. I did this by adding a hook into cucumber

Before do |scenario|
  puts "Cleaning Up LDAP Server"
  LdapConnect.new(:admin => true).clear_users!
end

And then my LdapConnect class (since multiple models might need to touch the ldap server, I can just pass around this object). I am using the ruby-net-ldap gem for LDAP interaction

class LdapConnect

  def initialize(params = {})
    ldap_config = YAML.load_file("#{RAILS_ROOT}/config/ldap.yml")[RAILS_ENV]
    ldap_options = params.merge({:encryption => :simple_tls})

    @ldap = Net::LDAP.new(ldap_options)
    @ldap.host = ldap_config["host"]
    @ldap.port = ldap_config["port"]
    @ldap.base = ldap_config["base"]
    @ldap.auth ldap_config["admin_user"], ldap_config["admin_password"] if params[:admin] 
  end

  def ldap
    @ldap
  end

  def clear_users!(base = "ou=people,dc=test,dc=com")
    raise "You should ONLY do this on the test enviornment! It will clear out all of the users in the LDAP server" if RAILS_ENV != "test"
    if @ldap.bind
      @ldap.search(:filter => "cn=*", :base => base) do |entry|
        @ldap.delete(:dn => entry.dn)
      end
    end
  end

end

So, my cucumber feature looks something like:

Feature: Check to make sure users can login
  In order to make sure users can login with the LDAP server
  As a user
  I want to make sure the user can login

  Background:
    Given I have the following users
    | email | password | user_class | first_name | last_name |
    | [email protected] | right_password | externalPerson | external | person |
    | [email protected] | right_password | internalPerson | internal | person |
    | [email protected] | right_password | adminPerson | admin | person |

  Scenario: Success Login Check
    Given I am logged in as "[email protected]" with password "right_password"
    Then I should be on the homepage

And finally the steps

Given /^I have the following users$/ do |table|
  # table is a Cucumber::Ast::Table
  table.hashes.each do |hash|
    hash[:password_confirmation] == hash[:password] unless hash[:password_confirmation]
    User.create(hash)
  end
end

Given /^I am logged in as "([^\"]*)" with password "([^\"]*)"$/ do |email, password|
  visit login_url  
  fill_in "Email", :with => email  
  fill_in "Password", :with => password  
  click_button "Login" 
end
Dan McNevin
+1  A: 

I've just been looking into this myself, and have come across the rather under-the-radar fakeldap gem.

http://github.com/aanand/fakeldap http://rubygems.org/gems/fakeldap

I may add to this answer with some experience after i've used it.

Glenjamin
That is awesome. Up to now, I've just been running a test LDAP server on 3389 and then basically dropping and recreating the whole root tree before each test. This should be very helpful!
Dan McNevin