Friday, December 7, 2007

Redirecting nginx to Tomcat.

I've got a JRuby on Rails application which is deployed on a Tomcat server. My Http server of choice is nginx. I wanted nginx to redirect one of my domains to the JRuby application. The default port that Tomcat listens on is 8080.

The following nginx configuration snippet solves this problem:

server {
server_name mydomain.com www.mydomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}

BTW, I never thought that my (basic) Russian language skills will be useful in my IT career. Most of the nginx related blog posts I found are in Russian language!

Thursday, October 18, 2007

Rails: How to unit test the formatting of model fields in the views.

In our Rails applications we often use Textile/RedCloth or some other libraries to have things like Post's content nicely formatted in the view. I use acts_as_textiled. This plugin simplifies the code a lot. All that is needed in order to make a certain field 'textilized' is this line:

class Post < ActiveRecord::Base
acts_as_textiled :content
end

The question that I want to focus on here is:

How to unit test that a certain field will be nicely formatted in the views?

lolcat - this not so hard
more funny pictures

As Jay Fields has already explained (he focused on testing validations in his article) there are two approaches:
The first one is based on listing all the cases that are important, like whether paragraph tags are correctly inserted or whether bold tags are correct. It may be sometimes useful but for me it's a code smell that for testing a single line in your codebase you need so many test lines of code. Additionally, the acts_as_textiled plugin is nicely tested/specified so why duplicate the code? I'd rather test some of those cases in my Selenium tests or functional tests and choose the second approach:

def test_content_is_nicely_formatted
Post.expects(:acts_as_textiled).with(:content)
load "#{RAILS_ROOT}/app/models/post.rb"
end

I'm using mocha here for setting an expectation that a class method called acts_as_textiled will be called (passing the field name argument) during the load time of the class file. This solution is not ideal. I don't like hardcoding the path here but I still find it simpler that the first approach.
This way testing of things like validations and acts_as_* calls becomes much simpler.

Tuesday, October 16, 2007

How to parse a chess PGN file using JRuby and Chesspresso

I have a lot of chess PGN files with many chess games inside. What I want, is to have some way of filtering this collection e.g. by player names or by opening. Ideally, I'd like to use either Ruby or Python to do that.

My first approach was to find a pure Ruby library and use it. Unfortunately, I couldn't find any good one. No luck with any Python module either. I didn't want to use .Net platform in this case, but I did a quick google search with no good results...

The last hope was the Java platform. This time I was lucky and found Chesspresso. A quick test proved that the library is mature, exposes a very nice API and is actually very fast.
Even though I have a lot of experience with Java language, I don't fancy implementing my projects in statically typed languages. I find Ruby or Python much more readable and testable.

My choice is now clear - JRuby.
include Java
require 'Chesspresso-lib'
include_class 'chesspresso.pgn.PGNReader'

pgn_reader = PGNReader.new 'twic675.pgn'

while game = pgn_reader.parse_game do
if game.white.include?('Shirov')
puts game
end
end
  • The output in my case is:
Shirov,A - Naiditsch,A 1/2-1/2 (2007.10.08)
Shirov,A - Almasi,Z 1-0 (2007.10.09)


deliverhappy.jpg
more funny pictures

Thursday, June 28, 2007

RSpec for acts_as_taggable

Requirements:

An empty post
- should be valid
- should have no tags
- should allow setting tags

A post with tags
- should show tags
- should be listed as tagged


Implementation:

class Post < ActiveRecord::Base
acts_as_taggable
end


RSpec:

describe "An empty post" do
before(:each) do
@post = Post.new
end

it "should be valid" do
@post.should be_valid
end

it "should have no tags" do
@post.tags.should be_empty
end

it "should allow setting tags" do
@post.tag_list = "tdd, rails"
@post.save
@post.tags.should_not be_empty
end
end

describe "A post with tags" do
before(:each) do
@post = Post.new(:tag_list=>"tdd, python, rails")
@post.save
end

it "should show tags" do
@post.tag_list.names.should == ["tdd", "python", "rails"]
end

it "should be listed as tagged" do
Post.find_tagged_with('tdd').should == [@post]
end
end


More details:
http://agilewebdevelopment.com/plugins/acts_as_taggable_on_steroids

Thursday, June 14, 2007

Testing Rails controllers with mock objects

One of the steps in my 15 TDD steps to create a Rails application article was using the mocking technique.
Mock objects were used in a test for a controller method. From the feedback I received I noticed that this technique is not very popular and requires a more detailed explanation. This article describes why you might want to use mock objects for testing your controllers and how it simplifies the testing setup and code. The mocking library I use in this article is Mocha.

Rails controllers

Before I go into details about testing Rails controllers, let's clarify what is the responsibility of a Rails controller.

Ideally, a controller method should only call one method on a model class. Sometimes the method on the model that we call is some kind of finder like Person.find(:all). The result of the method should then be passed to the view.
A Rails controller should be a thin layer between your model classes and the view part.

A sample implementation looks like that:

def learn
@word = Word.random
end

As we see, we call the 'random method on the Word class which represents some model part of our application. Then we pass the result to the view via @word.

Testing Rails controllers

Being aware of that, we know what we want to test:
A learn method should:

  1. call the Word.random method

  2. pass the result to the view


Problems with traditional approach to testing Rails controllers
Now, what if we simply construct the test like this:

def test_learn_passes_a_random_word
get 'learn'
assert_kind_of Word, assigns('word')
end

The first problem here is that it calls the Word.random method, thus accesses the (test) database. It means we need to have some fixtures loaded so that the random method can retrieve some word from it.
The second problem is that we only test the type (kind_of) of the object assigned to @word. It means we don't fully test the method. We could imagine an implementation of the learn method that passes the tests but does the wrong thing (by assigning any other object to @word). Not ideal.

Testing with mock objects

Fortunately, we can use mock objects here and solve both problems.
We will replace the Word.random method with a method that always returns an object that we prepared before. Another advantage is that:

We don't connect to the database from our unit tests which is A Good Thing.


The object that we prepare before can then be used to assert whether the one passed to the view was the same as the result of calling Word.random method.

random_word = Word.new
Word.expects(:random).returns(random_word)

As we see, we prepare a random_word object, which is simply a new instance of a Word class. The next line does two things:

  • expects(:random) - sets our expectation that the random method will be called

  • returns(random_word) - replaces the real implementation of the 'random' method with an implementation that always returns the random_word object.


Btw, we didn't have to create a new instance of Word here. We could have used Object() there and that would work fine. The crucial part is that we compare the objects we return from Word.random with the one assigned to @word.

What is an expectation?

An expectation is almost like an assertion. The difference is that we set it before the actual call to the method that we test. The test will fail if the expectation isn't met.

We now extend the test with a call to the 'learn' method that we test:

random_word = Word.new
Word.expects(:random).returns(random_word)
get 'learn'

This test should now pass with the following implementation:

def learn
@word = Word.random
end


We also want to test that the object was assigned to @word, so we need an additional line with assertion:

def test_learn_passes_a_random_word
random_word = Word.new
Word.expects(:random).returns(random_word)
get 'learn'
assert_equal random_word, assigns('word')
end


The assertion tests the equality of the random_word object and the @word (we access it using assigns('word')). It's possible only thanks to the fact that we replaced the real Word.random method and have a reference to the result of this method.
Benefits

  • not connecting to a database
  • no need for preparing fixtures
  • faster tests
  • controller tests are less fragile for model changes

Drawbacks

  • some developers may find the tests less readable
  • if you rename the model method, the controller tests will still pass
  • increased need for some integration tests - Selenium or standard Rails integration tests


Conclusion

I hope that this article sheds more light on what are mock objects. I strongly recommend trying to add some tests like that to your test suite. If you want to read more about mocking you should first go to the classic Martin Fowler's article on Mock Objects. After that go to the Jay Field's blog. You can also find some interesting examples on the Mocha website.

Thursday, May 31, 2007

How to programmatically submit a POST form using IronPython

Sometimes you may want to download a web page that is a result of submitting a form that uses a POST method. The code below shows how to do that using IronPython.

  1. prepare a request object, that is created for a given URI.
  2. write the PARAMETERS string to the request stream.
  3. retrieve the response and read from its stream.


URI = 'http://www.example.com'
PARAMETERS="lang=en&field1=1"

from System.Net import WebRequest
request = WebRequest.Create(URI)
request.ContentType = "application/x-www-form-urlencoded"
request.Method = "POST"

from System.Text import Encoding
bytes = Encoding.ASCII.GetBytes(PARAMETERS)
request.ContentLength = bytes.Length
reqStream = request.GetRequestStream()
reqStream.Write(bytes, 0, bytes.Length)
reqStream.Close()

response = request.GetResponse()
from System.IO import StreamReader
result = StreamReader(response.GetResponseStream()).ReadToEnd()
print result

Wednesday, May 30, 2007

How to download a web page using IronPython

Downloading a web page is a common programming task. Here are two snippets of code that show how to do it with IronPython. The code was tested on Windows and Mac (with Mono).

Using the WebClient class

from System.Net import WebClient
dataStream = WebClient().OpenRead('http://google.com')
from System.IO import StreamReader
reader = StreamReader(dataStream)
result = reader.ReadToEnd()
print result

Using the WebRequest and WebResponse classes

from System.Net import WebRequest
request = WebRequest.Create("http://google.com")
response = request.GetResponse()
responseStream = response.GetResponseStream()
from System.IO import StreamReader
result = StreamReader(responseStream).ReadToEnd()
print result