Sunday, 15 July 2007

Firefox at 1.8 GB of RAM

One of the reasons why I hate Firefox is the memory that it uses. It needs about 100MB - 200MB for 10 tabs, or even more if one of these is Gmail or Google Reader. If you open more tabs and switch quickly between them etc, the browser just slows down and needs a restart.

But this is actually nothing compared to what Firefox managed to do today. I was navigating Google maps with about 10 other tabs opened at the same time, when this happend:


My box has 'only' 2 gigs of RAM. I guess Firefox would have used even more if there was more to use ...

Luckily, I didn't have to restart my box, just the browser ;-)

Sunday, 3 June 2007

Grails 0.5.5 - testing controllers with Mocks and Expando

In this blog entry I would like to show you how to unit test a typical 'update' action in Grails using Groovy Mocks and the ExpandoMetaClass.

Let's assume we have an action like this:
 
 def updateword = {
     def word = Word.get( params.word_id )
     if(word) {
         word.pl = params.word_translation
         if(word.save()) {
             render("OK")
         }
         else {
             render("Error updating word")
         }
     }
     else {
         render("Word does not exist")
     }
 }
In brief, it updates a Word instance by getting a Word from the database, modifying its 'pl' property and saving it back to the database.

Now, how would you unit test the execution path where the "Error updating word" message gets rendered? To do that, you need a scenario where a Word instance gets returned from the database but fails to save back after the update operation. Here is how you can do it using Mocks and Expandos:
 void testUpdateExistingWordSaveFailure() {
     def mock = new MockFor(Word)
     def fakeWord = new Expando(save: {false})
 
     mock.demand.get { fakeWord }
     mock.use {
         def wc = new WordController()
         wc.params.word_translation = "tak"
         wc.updateword()
         assertEquals "Error updating word", 
                      wc.response.delegate.contentAsString
     }
 }

The flow of the test is as follows:
  1. Create a mock for the Word class
  2. Craete a fake word instance (Expando) which replaces the 'save' method
  3. Demand the Word class to return the faked word when the get method is called (exactly once)
  4. Use the mock and call the updateword closure
  5. Assert if the correct message was rendered to the browser
See the Unit & Integration Testing Controllers page to understand the last step - getting a text from the response.

Saturday, 26 May 2007

Grails 0.5 Unit Testing - other issues

I have mentioned already about slow unit testing in Grails 0.5. Apart from that, there are several other bugs:
Luckily, there are workarounds for all these bugs (good news if you are stuck). Check the grails-user group for more details (clicking one of the bugs above should take you to the description and solution).

The good news is, that all the issues seem to be fixed in the current 0.5.5 snapshot (downloaded on 26th of May)! Suggest that you give it a go, or even upgrade your projects to version 0.5.5.

Be careful however when upgrading to 0.5.5. Tests have been moved from 'grails-tests' to 'test' folder, therefore 'grails test-app' will give you:

No tests found in test/unit to execute ...
No tests found in test/integration to execute ...

As you can see, tests have been separated into two categories: unit and integration. I have noticed however, that unit tests for domain classes are being generated under the 'integration' test folder. Looks like a new bug, though more likely that the test separation has not been fully implemented (and tested :)) yet.

Update:
Actually, it is not a bug. Typical unit tests for domain classes in Grails are in fact integration tests with all the dynamic methods and properties injected by the framework. Plain unit tests can be created, too by running the grails create-unit-test command. Read more on the Grails Unit Testing page.

Monday, 21 May 2007

Grails Unit Testing not agile

Don't be surprised if you give Grails unit testing a try. I've done that recently and must say it is not agile at all. At least not yet (Grails 0.5).

As for now, it takes approximately 25 sec on a pretty fast box (my PC is a 3.2 GHz Dual Core with 2GB RAM, Os WinXp) to run a single unit test. Why so long? Surely, unit tests should run faster.

Update: I've just run grails test-app on my new Ubuntu 7.04. To my surprise, a single unit test run takes only 17 sec. That's a big difference comparing to 25 sec on WinXp.

I have found the answer on the grails user group. Graeme Rocher, the project lead of Grails, in reply to a similar issue says:
"We're separating out unit and integration tests so that unt tests will
run quicker. At the moment every test is an integration test, hence
why it takes long to bootstrap" (Graeme's post)

The slow unit testing should be improved in Grails 0.5.5, as Graeme is working on improvements to that. Can't wait to try this out as TDD on Grails can be really exciting then!

Apart from that there is another small issue, though. Some have already experienced that (see this post on the grails-user group), too. If a unit test fails it does not tell you what went wrong. All you can see is the 'test failed' message. Quite confusing, especially if you are used to JUnit's detailed error messages.

Luckily, you can find the cause. Again, the grails-user group is where I've found the answer. The detailed test reports sit under target/test-reports folder. They are available in different formats, including plain text, xml and html. You can find the detailed message there, plus a very long stack trace ;-) The only trouble is that you waste even more time finding the cause of a unit test failure...

And here I can give one hint that makes it faster. If you open one of the detailed reports in a text editor that checks for file modifications, it would reload the report automatically after each test run ;-)

Saturday, 19 May 2007

Joke on Rails

Just inside the gates of heaven, St. Peter sits at a desk checking people in.

Peter: .Welcome to heaven. Programming language?.

The man at the front of the line says, .Smalltalk..

Glancing at his clipboard, Peter says, .Room 33. Be very quiet as you pass Room Six..

The process repeats itself with the next person in line:

Peter: .Welcome to heaven. Programming language?.

Person #2: .Common Lisp..

Peter: .Room 17. Be very quiet as you pass Room Six..

The next person moves to the front of the line with a look of curiosity on her face.

Peter: .Welcome to heaven. Programming language?.

Person #3: .Python..

Peter: .Room 54. Be very quiet as you pass Room Six..

Person #3: .Why do you keep telling us to be quiet as we pass Room Six?.

Peter: .Because the Ruby on Rails People are in Room Six, and they think they're the only ones here.

Found here.

Thursday, 10 May 2007

TDD on Rails on Mac

Together with Andrew, we had an instructive TDD session on Rails yesterday. It was quite a new experience especially for me as I had never had a Mac in my hands before :). It took me about 2 hours to get used to it. However, there is still one thing I don't like and can't understand - where is the 'Del' button on Mac??!! Hope there is a good explanation for not having it ...

Anyway, we started from scratch repeating the 15 TDD steps to get the basic app running. The app itself is very simple - a kind of english/polish dictionary with the guess/learn option. The next thing after the 15th step was to add some content to the database so the user can play around and have fun guessing new words. Andrew talks in more detail in his last post how we tested and implemented that. I must admit however that it was a real fun for a (still!) Java programmer like me to switch to Ruby for a while. Just see how little code we had to write to achieve the following:
  • check if a Word has a translation

def translated?
pl and en
end
  • return a random and translated word

def self.random
(Word.find(:all).select {|word| word.translated?}.sort_by {rand})[0]
end

Can you imagine how would this code be implemented in Java?

Having done some TDD before I realized again what really matters when you test drive your application. TDD changes the way of thinking of the code you are going to write. As Andrew said, it is all about design, not necessarily about testing itself. The tests you write is some sort of (positive) side effect - you just get them as you go along.

The other thing I'd like to mention here is YAGNI (You Arent Gonna Need It). Perhaps a bit off topic, nevertheless that's what came to my mind yesterday, too.
Having written many lines of good looking and performing code I had to stop worrying about code like this:


(Word.find(:all).select {|word| word.translated?}.sort_by {rand})[0]

Certainly getting all the words from the database does not look nice at first glance. But have a think - is that really going to work very slow and cause any problems? Not really, unless you have hundreds or thousands of users, which doesn't happen so quickly. So don't bother until this becomes a real problem. And what is the most important here - be productive and don't waste your precious time for improvements that don't have any business value.

Tuesday, 16 January 2007

Groovy in System Tray

As of Java 1.6 there is a cool feature available - System Tray. Actually, System Trasy plus nice notifications which look like a balloon on Windows. Now you can put Duke next to your favorite icons, if you like!

An example source code is available on the java docs page. Indeed, it is an example and even not a fully working one. I am not going to rewrite it - I believe Sun it works. Instead, I will try making the code more ... groovy ;-)

Here it is, System Tray example in Groovy:

import java.awt.Image
import java.awt.AWTException
import java.awt.MenuItem
import java.awt.PopupMenu
import java.awt.SystemTray
import java.awt.Toolkit
import java.awt.TrayIcon

def trayIcon = null

def exit = { e ->
println "Exiting ..."
System.exit(0)
}

def showMessage = { e ->
trayIcon.displayMessage("Action Event",
"An Action Event Has Been Peformed!",
TrayIcon.MessageType.INFO)
}

if (SystemTray.isSupported()) {
def tray = SystemTray.getSystemTray()

def image = Toolkit.getDefaultToolkit().
getImage("duke16.gif")

def popup = new PopupMenu()
popup.add(new MenuItem(label:"Exit", actionPerformed:exit))

trayIcon = new TrayIcon(image:image, tooltip:"Tray Demo",
popup:popup, imageAutoSize:true,
actionPerformed:showMessage)
try {
tray.add(trayIcon)
} catch (AWTException e) {
println e
}
} else {
prinltn "System Tray not supported"
}


As you can see it is possible to make Duke shout: Groovy did it! However, the code looks more like java. And what is worse, I am afraid we can't make it more groovy, using Swing Builder (the popup menu could be 'built'). The Tray functionality sits under java.awt package, which the Swing Builder does not support I think (well, it did not work for me). Luckily, we can still use Groovy's closures instead of Action Listeners.

Nevertheless, it works fine and - what is worth stressing here - it is platform independent! I have run the example successfully on GNOME, KDE and Win Xp desktops. Here are my screenshots:


GNOME

KDE

Windows Xp

And two Dukes, if you would like to run the example on your desktop



Oh, and one more thing. If you are curious what other dynamic languages support System Tray, my friend, Andrzej, shows how to do this in Iron Python. See his article here.