From: Joe Van Dyk Date: 2005-06-09T07:21:35+09:00 Subject: Re: Test-Driven Development in GUIs On 6/8/05, Joe Van Dyk wrote: > On 6/7/05, Joe Van Dyk wrote: > > Hi, > > > > Anyone have any tips for writing GUIs in Ruby (using Tk, for example) > > using a TDD approach? > > > > A google search gave me > > http://approximity.com/ruby/rubytk.html#testfirst, which claims that > > some guy is writing a book on TDD for GUIs, using Ruby/Tk as preferred > > language/toolkit. That section links to > > http://www.c2.com/cgi/wiki?TestFirstUserInterfaces, while informative, > > doesn't contain any information that I can see on a book. > > > > Say, for the purposes of this discussion, say that you had a small Tk > > application that monitored the status of ten websites. If the website > > was up and was active and performing well, the GUI would display a > > "Working!" message and perhaps showed data about the site (latency, > > bandwidth, whatever). The GUI could also display graphs of > > uptime/downtime, view history reports, and moderately complex GUI > > stuff like that. > > > > How would you go about testing that GUI application? There's a strong > > chance that if I get some good ideas from my head and from this > > discussion, that I'd write that application and also write a HOWTO on > > TDD with GUIs. > > > > Thanks, > > Joe > > > > Here's a very simple example of a quick UI app that's unit tested. > Comments appreciated. > > If you run the application like 'ruby file.rb test', the tests will > get run. If you run it like 'ruby file.rb', the gui will be > displayed. In a real application, the tests would be in their own > file, of course. > > As I do more research, I'll post more examples. Here's another iteration, this time the result is being displayed to a TkLabel. The tests check to see if the label has the correct value. So, when testing GUIs, is it good practice to have all the (tested) widgets be available through attr_accessor (or attr_readers)? How else can you test them? require 'tk' require 'test/unit' class App attr_accessor :sum, :inc_button, :display_button, :power_2_button, :output_label def initialize @sum = TkVariable.new @sum.value = 0 root = TkRoot.new :title => 'my app' @inc_button = TkButton.new root @inc_button.text = "Increment" @inc_button.command = proc { inc } @inc_button.pack :expand => true @power_2_button = TkButton.new(root) @power_2_button.text = "Power of 2" @power_2_button.command = proc { power2 } @power_2_button.pack :expand => true description_label = TkLabel.new description_label.text = "Result:" description_label.pack :expand => true @output_label = TkLabel.new @output_label.textvariable = @sum @output_label.pack :expand => true end def inc @sum.value = @sum.value.to_i + 1 end def power2 @sum.value = @sum.value.to_i * @sum.value.to_i end end class TestApp < Test::Unit::TestCase def result(app) app.output_label.text.to_i end def testInc app = App.new assert_equal 0, result(app) app.inc_button.invoke assert_equal 1, result(app) app.inc_button.invoke assert_equal 2, result(app) end def testPower2 app = App.new assert_equal 0, result(app) app.power_2_button.invoke assert_equal 0, result(app) app.inc_button.invoke assert_equal 1, result(app) app.power_2_button.invoke assert_equal 1, result(app) app.inc_button.invoke assert_equal 2, result(app) app.power_2_button.invoke app.power_2_button.invoke assert_equal 16, result(app) end end if ARGV[0] != 'test' App.new Tk.mainloop exit end