Friday 12 December 2008

Integration testing

I found this to be quite frustrating. Integration testing appears to be a relatively recent addition to Rails (since 1.1 I think), and pehaps for that reason there is not much on the web that explains the basics of how to do it. Coupled to that, my application is using an authentication system that I copied from a web site, and so I was just not that familiar with what is supposed to happen (at least, when I started; I know it a lot better after going through this). Also, the authentication system has some odd quirks, like defining session (rather than sessions) as a route, for a controller called sessions_controller.

Integration testing can be thought of functional testing for multiple controllers. This allows you to set up involved "stories" in which the user does a sequence of actions. Rails automatically generates unit and functional tests for you when you create a scaffold, but not an integration test (as it is not specific to one model/controller). However, there is a script to do the job for you.
ruby script/generate integration_test GeneralStories

Here is a test for the user authentication mentioned before:
  def test_authentication
user_bob = {:login => 'bob', :username => 'Robert',
:email => 'test@here.com', :password => '12345678',
:password_confirmation => '12345678', }
new_password = 'new_secret'

goes_to_home_page
goes_to_login
fails_to_log_in_with user_bob
goes_to_signup
signs_up_with user_bob
goes_to_login
logs_in_with user_bob
goes_to_change_password
changes_password user_bob, new_password
logs_out
goes_to_login
logs_in_with user_bob
goes_to_home_page
end

The code here is easy enough. A test method has to start test_ so Rails knows it is a test. First a hash is set up with details for a user, as well as a new password. Thereafter, it runs through a sequence of methods, each one corresponding to a single page download to the user (purely because that seems a convenient way to break it up). Reading down the sequence, we can read the story. The user goes to the home page, attempts to log in, but fails, then signs up, successfully logs in, changes his password, logs off, and logs on again, ending up back at the home page.

All the tricky stuff is, of course, hidden away in those methods. I am just going to look at the two involved in changing the password to illustrate the methodology.
def goes_to_change_password
get "/change_password"
assert_equal 200, status
assert_equal "/change_password", path
end

This corresponds to the user clicking on the "Change Password" link. The get command is equivalent to an HTTP GET. You then check the HTTP result is 200, and the returned page is correct. The next method is rather more complicated.
def changes_password(user_options, new_password)
post "/accounts/update",
:old_password => user_options[:password],
:password => new_password,
:password_confirmation => new_password
follow_redirect!
assert_equal 'Password successfully updated.', flash[:notice]
assert_equal "/", path
assert_equal 200, status
user_options[:password] = new_password
user_options[:password_confirmation] = new_password
end

Now the post command is invoked, for HTTP POST. The values on the form are sent in the form of a hash. Rails usually expects a hash of a hash here, which would look like this (and in the controller would be accessed with params[:user]):
  post "/accounts/update",
user => {:old_password => user_options[:password],
:password => new_password,
:password_confirmation => new_password}

I am not sure why my authentication system was set up differently; perhaps for older versions of Rails. If the action is successful, the user is redirected, and we want to see where that goes, so the next statement, follow_redirect!, does just that. Then we check everything: the flash notice should confirm the change, the path should be at the root and the HTTP status should be 200. Finally, a little bit of house-keeping; the user hash is updated with the new password ready to test logging on in a later step.

Multiple Sessions
In the background, Rails has a session object on the go, and this allows your test to proceed. If you want to you can invoke the session explicitly. One reason to do that would be to test what happens if multiple users are logged in at the same time (though I am suspicious that people use this when it is not necessary). It goes something like this (based in part on code here):
def test_signup_new_person
user_bob = {:login => 'bob', :username => 'Robert',
:email => 'test1@here.com', :password => '12345678',
:password_confirmation => '12345678'}
user_mary = {:login => 'mary', :username => 'Mary',
:email => 'test2@here.com', :password => '12345678',
:password_confirmation => '12345678'}
new_password = 'new_secret'

open_session do bob
open_session do mary
bob.extend(MyTestingDSL)
mary.extend(MyTestingDSL)

bob.goes_home
bob.goes_to_login
bob.fails_to_log_in_with user_bob
bob.goes_to_signup
bob.signs_up_with user_bob
mary.goes_to_signup
bob.goes_to_login
bob.logs_in_with user_bob
mary.signs_up_with user_mary
bob.goes_to_change_password
bob.changes_password user_bob, new_password
mary.goes_to_login
mary.logs_in_with user_mary
bob.logs_out
bob.goes_to_login
bob.logs_in_with user_bob
bob.goes_home
end
end
end

The test itself is more or less the same, except that the sequence is wrapped up in a block for open_session, and the session is addressed directly. This allows two sessions to be set up, bob and mary. The methods are set up the same, but again are wrapped up, this time in a module called MyTestingDSL. The module is mixed in to the session before the methods are invoked.

Finally...
I found it helpful to end my assertion with a call to this method:
def flash_me
"Error encountered. Flash[:error]=#{flash[:error]} Flash[:notice]=#{flash[:notice]}"
end

For example:
assert_equal 200, status, flash_me

If the assertion fails, you will get told the contents of flash. The method definition needs to be inside the module, if you are using sessions explicitly.

I found trouble-shooting a test failure to be something of a nightmare. The test informs you at which line in the test line it failed, but that gives you no clue about when in your actual code the problem is. It will report the same error (<200> expected but was <500>) for anything from an action that is not recognised, to an exception thrown in your model or a misnamed column. The best solution I found was to pepper the code with statements assigning values to the flash, which would then show up using the flash_me method above. Here is an example (with additional lines in red):
def qualify
flash[:notice] = 'here'
begin

@worksheet_meta_data = WorksheetMetaData.find(params[:id])
flash[:error] = '@worksheet_meta_data = nil' if @worksheet_meta_data.nil?
s = @worksheet_meta_data.qualify current_user.username
if s.nil?
flash[:notice] = "WorksheetMetaData was qualified (#{@worksheet_meta_data.qualified_by})."
else
flash[:error] = "Qualification failed: #{s}"
end
rescue Exception => ex
flash[:error] = "ex=#{ex}"
end

redirect_to(@worksheet_meta_data)
end

I also commented out the redirect! statement, so after the get or post, there is the assert, with a flash_me to see the result. The first extra line will confirm that the method is being invoked (are you using the right controller, action, and id; these might give a 404 error if not). Then everything up to the redirect is wrapped in a rescue block so any errors thrown get recorded in flash[:error]. Inside the block, I check

I would be interested to hear of any better ideas.

Struggling with Ruby: Contents Page

Wednesday 10 December 2008

Ruby Classes

In Ruby, everything is an object. You can find the class of an object with my_object.class, which returns an object of the Class class.
10.class  # => Fixnum
10.class.class # => Class
"Hello World".class # => String

If you do not have an instance of a class, you can determine the name of the class using the inspect method (this might be useful if you are in a class method in a super class and want to know the subclass).

The superclass method will produce the superclass.
10.class.superclass # => Integer
10.class.superclass.superclass # => Numeric
10.class.superclass.superclass.superclass # => Object

As in Java, everything inherits from Object.

You can check if an object is of a certain class using the is_a? method. This will return true if the object is of the given class or of a subclass of it.

"Hello World".is_a? String # => true
"Hello World".is_a? Fixnum # => false
"Hello World".is_a? Object # => true


What methods are there?
The methods method returns an array of method names for an object, while a call on methods from the class will produce an array of class methods.

"Hello".methods
String.methods

There are also methods that list more particular methods, such as public_instance_methods or private_methods.

You can also check if an object has an associated method with the respond_to? or method_defined? methods. Unlike methods, these two methods will not find private methods. The respond_to? method really does what it say - it tells you if the object will respond to the method call, rather than if the method exists. Often an object can respond to method calls where there is no method present using the method_missing functionality (discussed here). Rails uses this a lot. For a model, Post, calling Post.methods will locate no find methods, but the respond_to? method confirms they are there. method_defined? will tell you if the method actually exists.

"Hello".respond_to? 'length' # => true
String.respond_to? 'constants' # => true
Post.respond_to? 'find_by_name' # => true
Post.method_defined? 'find_by_name' # => false


See also:
http://www.ruby-doc.org/docs/ProgrammingRuby/html/ospace.html

Dynamically adding a method
You can add a method to a class at runtime, using the define_method method. Note that this method is private (so the first attempt below results in an error), and so must be invoked with the send method.
a = "what".class.define_method('hello') {p 'Hello World'}
# => NoMethodError: private method `define_method' called for String:Class
a = "what".class.send(:define_method, 'hello') {p 'Hello World'}
# => #<Proc:0x08cb9294@(irb):17>
irb(main):018:0> "say hello".hello
# => Hello World

You can even replace existing methods:
"what".length
=> 4
a = "random".class.send(:define_method, 'length') { 10 }
=> #<Proc:0x08caaf28@(irb):21>
"what".length
=> 10

Alternatively (and more simply), you can define methods for existing classes just like you would for your own class. The first example could be done like this:
class String
def hello
p 'Hello World'
end
end

I can see security issues here if someone can change how your classes' behave at runtime, and how do you comprehensively unit test if you cannot be sure how the String class behaves? All part of the fun of a dynamic language...

ObjectSpace
ObjectSpace is the Ruby reflection mechanism. It is a module that tracks all the current objects. You can list them with this:

ObjectSpace.each_object{ i puts i}


I had over 8000 objects in one IRB session. You can specify the class of an object to list, for example, this will list all objects of the Class class (only 466 of them):

ObjectSpace.each_object(Class) { i puts i}


Creating new objects dynamically
You can use the ObjectSpace to create a new object from a string containing the class name (see here), but I prefer using the eval method. eval simply interprets a given string as Ruby (like the synonymous method in JavaScript). The eval method is none too fast, but I do not know how it compares to using ObjectSpace.

def create_object class_name
eval("#{class_name}.new")
end


Struggling with Ruby: Contents Page

Friday 5 December 2008

Ruby Methods Part 2 - Not Overloading!

Method overloading is a common feature of several object-orientated languages. It allows the same name to be used for methods that perform the same, but accept different parameter types. Here is an example in Java:
  // Method overloading in Java
public int myMethod(String name, int age, int shoeSize) {
// do stuff
}

public int myMethod(String name, int shoeSize) {
myMethod(name, 0, shoeSize) {
}

public int myMethod(int age, int shoeSize) {
myMethod("", age, shoeSize) {
}

public int myMethod() {
myMethod("", 0, 0) {
}

// Invoking
public int main(String[] args) {
myMethod("F2Andy", 43, 8);
myMethod("F2Andy", 8);
myMethod(43, 8);
myMethod();
}

Ruby does not support method overloading, something I found very surprising at first. I suspect the reason is the way Ruby handles objects. Java is very strict that what gets sent to a method is exactly what the method expects. That gives (I would imagine) more robustness, but at the loss of flexibility.

Ruby has what could be described as "method over-writing" instead of overloading. In this example, the second test method over-writes the first:
def test s
puts "hello test"
end

def test
puts "goodbye test"
end

test # Causes "goodbye test" to be printed
#test "my string" # Causes an error:
# wrong # of arguments(1 for 0) (ArgumentError)
See here for how to use alias if you still need to access the old methods:
http://www.zweknu.org/blog/index.rhtml?start=77&

Default values and dynamic typing
Ruby has four tricks to mimic method overloading, and I am going to bundle the first two together. The first is default values in the method definition. Simply give a parameter a default value and it becomes optional. The second is the way Ruby handles objects; dynamic typing. Ruby does not care what sort of object you throw at a method, leaving the method writer the chance to handle different classes in different ways. In the next example the method has a default value - "default" - but the method is written in such a way that it will accept any class of object:
def test t = 'default'
puts "goodbye test t=#{t}"
end

test # => "goodbye test t=default"
test 34 # => "goodbye test t=34"

Something to consider, then, is how you handle unexpected objects in your class. One way is to ignore the issue, making the assumption that the method user knows what he is doing and any problems will be caught by the Ruby system.
def test t = 'default'
puts 'goodbye test t=' + t
end

test "one" # => "goodbye test t=one"
#test 2 # => can't convert Fixnum
# into String (TypeError)

Let us look at another example to see what options we have:
def test n
puts n.abs
end

test -4 # => 4
test 2 # => 2
#test "three" # => undefined method `abs'
# for "three": String (NoMethodError)

Rather than relying on your own method calls to generate errors, you might prefer to check that what you receive in your method is what you are expecting. You can then be quite clear about what exceptions your method is throwing, and more importantly, you will not have exceptions thrown half way through you method leaving the system in an unpredictable state.
def test n
raise StandardError.new("Oops, not a Fixnum") unless n.is_a? Fixnum
puts n.abs
end

test -4 # => 4
test 2 # => 2
test "three" # => Oops, not a Fixnum
# (StandardError)

Then again, perhaps you do not care what class the object is. The important question is whether it will behave as you expect. Instead of testing that it is of the right class, you could test that it responds to the appropriate methods calls. In this next example, a new method, abs, is added to the String class (how that is done was the subject of another post). Now the test method checks that the object it is given will respond to the necessary method call. This technique offers a lot more flexibility, but does rely on the API user sending sensible objects to the method. Does it really make sense that a string should return the ASCII code of the first character when asked for its absolute value? However, I would say that that is up to the API user; he has the responsibility now of ensuring the object he sends makes sense. You would need to check for each and every method call in your code.
class String
def abs
self[0]
end
end

def test n
raise StandardError.new('Oops, object does not respond to abs') unless n.respond_to? 'abs'
puts n.abs
end

puts "three".abs # => 116
test -4 # => 4
test 2 # => 2
test "three" # => 116

What would have happened if I had defined the abs method on String to return a string, rather than a Fixnum?
Using hashes for parameters
The third trick is to use a hash, and this is done throughout Rails. In the next example, the method expects a hash. Note that the default is set to be an empty hash, to avoid errors with nil.
def test options = {}
puts "hello #{options[:name]}"
end

test # => "hello "
test "here" # => "hello "
test :name => 'F2Andy' # => "hello F2Andy"

Compared to method overloading, there are advantages on both sides. If you have an existing method and you want to add overloading, it is no problem in Java. In Ruby, chances are your existng method is not expecting a hash and you either have to change your existing method calls or write the new method to expect either a hash or the original type. However, if your Ruby method already accepts a hash, adding more parameters becomes trivial - just add them to method calls if desired, and use in the method code where needed.

Variadic functions
Finally, Ruby supports variadic functions. These are methods that accept a vaiable number of parameters. In Ruby this is indicated by an asterix in the method parameter list, before the last parameter. This will then become an array holding all the "left over" values. Here is an example:
def vari_method name, *values
puts name
values.each { |x|
puts " -#{x}"
}
end

vari_method 'fruit', 'apple', 'banana', 'pear'

When vari_method is invoked, 'fruit' goes into the name variable, and the three other strings are collected into a single array, values. The method prints the name, then lists each member of the array. There is no reason for the members of the array to be of the same class or in any way connected to each other.

Struggling with Ruby: Contents Page

Thursday 4 December 2008

Ruby Methods Part 1 - The Basics

A Ruby method definition starts with the keyword def followed by the method name and the parameter names, and ends with the keyword end.
def test
puts "Hello World"
end

test # Causes "Hello World" to be printed

Note that unlike Java and C#, Ruby does not require the return type or the parameter types to be stated. Every Ruby method returns a value. In the above example, puts returns nil, and as this is the last statement in the method test, test will also return nil. The return keyword is entirely optional (though necessary if you want to jump out of the middle of a method, of course).

Visibility
By default, all methods are public; they can be accessed from anywhere by anything.

Private methods can only be accessed from with the class and (unlike Java et al) its subclasses. That said, you can access private methods from anywhere using the send method, or modify their visibility on-the-fly, so it would seem that this is more advisory than anything else; the API writer is telling you that you probably should not use those methods.

The private keyword indicates that all subsequent methods (until public or protected is encounted) will be private.
class MyClass
def public_method
puts "In public_method"
end

# You can access private methods within the class
def private_via_public_method
puts "private_via_public_method"
private_method
end

private # Flags all subsequent methods
# as private

def private_method
puts "In private_methodstance_method"
end
end

class MySubClass < MyClass
# You can also access private methods
# within any subclass
def private_via_subclass_public_method
puts "private_via_subclass_public_method"
private_method
end
end

mc = MyClass.new
mc.private_via_public_method
mc.public_method
#mc.protected_method # Protected method
# not visible
#mc.private_method # Private method
# not visible

mc.send :private_method # Private method
# accessed with send

# Visibility can be changed dynamically
class MyClass
public :private_method
end

mc.private_method # Private method is
# now visible

The third visibility type is protected, which is a little more esoteric. The protected visibility is very similar to private, except that protected allows you call method from a different object, as long as that object is of the same class or subclass. To put it another way, private is restricted to the specific object, protected is restricted to the class.
class MyClass
# You can access private methods on the
# object within the class
def private_via_public_method
private_method
end

# You can access protected methods on another
# object within the class
def protected_via_other_public_method
mc = MyClass.new
mc.protected_method
end

# This will fail
# You cannot access private methods on another
# object, even within the class
def private_via_other_public_method
mc = MyClass.new
mc.private_method
end

protected
def protected_method
puts "In protected_method"
end

private
def private_method
puts "In private_methodstance_method"
end
end

The important point here is that both private and protected methods can only be used with the class (or subclass), but that private methods are further restricted to calls that do not require the dot operator.

As an aside, in Ruby all constants are public, and all variables are private

Class methods
Class methods are methods that are applied to the class rather than to a specific instance of the class. The most important example of a class method is new; in Rails the find method is also used very frequently.
s = String.new "My string"  # Equivalent to
# s = "My string"
post = Post.find :first # gets the first record
# from the posts table

As can be seen, class methods are invoked by using the class name, rather than the object, and as in the examples above they are often used to create or retrieve instances of the class.

Class methods are written much like instance methods, but with the keyword self before the method name. You cannot call a class method from an instance of the class, or call an instance method from the class itself. This does mean you can have a class method with the same name as an instance method.

See the next section for an example of a class method.

The initialize method
I have already mentioned the new class method. What this does is create a new instance of the object, and then it invokes the initialize method, if it exists. The initialize method is always private; there seems no way to change that. However, you can invoke it from within your class.

The following code illustrates the use of initialize and class methods.
class MyClass
def initialize
puts "In initialize"
end

def self.class_method
puts "In class_method"
end

def instance_method
puts "In instance_method"
end
end

MyClass.class_method # Prints "In class_method"
mc = MyClass.new # Would cause error; cannot call class methods on an object
#mc.class_method # Prints "In initialize"
mc.instance_method # Prints "In instance_method"


Class initialize method?
Sometimes you might want to do something to set up your class. You want it to run before any instances and created. I believe Rails does this for ActiveRecords, inspecting the database to see what fields are present, so it will know how to handle requests, rather than inspecting the database each time a request is made.

There is no method that supports this, you just put your code straight into the class definition.
class MyClass
p 'This will be printed when the class is loaded'

def initialize
p 'This will be printed when an object is instantiated'
end
end


Multiple return results
Pretty much every modern language allows you to send multiple arguments to a function/procedure/method. How many allow you to return multiple arguments? Certainly not the C derivatives, and really I cannot see why that should be so. At the machine code level, I would assume there is no difference. I would guess the reason is that C is based on a mathematical concept of functions, F = f(x,y,z), and Java and C# had followed suit.

Not so Ruby, which allows you to return as many values as you like. Here is a trivial example to illustrate that:
def test
return return 1, 'two', 3
end

a, b = test
p a # => 1
p b # => "two"

a, b, c, d = test
p a # => 1
p b # => "two"
p c # => 3
p d # => 4

Note that in this case the return keyword is required. What is actually returned is an array containing each each return value. This can lead to confusion...
def tester
return 3, 6
end

def output x, y = nil
p "x=#{x} y=#{y}"
end

x, y = tester
output x, y
# => "x=3 y=6"

output tester
# => "x=36 y="

The first call to tester correctly gets the two values assigned to the two variables. However, the second fails; the array is passed directly to the output method, which has no clue about the context, and just sees an array. What is really happening is a bit of trickery. Ruby does not pass back multiple values at all; it just passes back an array when multiple values are used with return. Meanwhile, at the other end, Ruby allows multiple varaibles to be set from an array.
x, y = [7, 6]
output x, y

Overall we have the illusion of muliple returns.

blog on dynamically creating methods:
http://ola-bini.blogspot.com/2008/05/dynamically-created-methods-in-ruby.html

Struggling with Ruby: Contents Page