Test-Driven Development in GUIs

Discussion in 'Ruby' started by Joe Van Dyk, Jun 8, 2005.

  1. Joe Van Dyk

    Joe Van Dyk Guest

    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
     
    Joe Van Dyk, Jun 8, 2005
    #1
    1. Advertising

  2. TDDing UI is hard, because it's a side-effect, rather than a return
    value or a parameter. I don't know the half of it. Nor, for that matter,
    know how to use Tk. I present to you a "Hello world" example.

    require 'test/unit'

    class Greeter
    def self.greet
    puts 'Hello, world!'
    end
    end

    class MockGreeter < Greeter
    class << self
    attr_reader :eek:ut
    def puts(*args)
    @out = @out ? [] : args
    end
    end
    end

    class TestGreeter < Test::Unit::TestCase
    def testGreet
    MockGreeter.greet
    assert_equal ['Hello, world!'], MockGreeter.out
    end
    end

    Subclass and override puts. Dependency injection doesn't help here. You
    can have greet take a Module as a parameter, and call module.puts, but
    you still need to test the container, and make sure it's passing Kernel
    to the greet method.

    Sorry, that's the short version. I gotta go.

    Devin
     
    Devin Mullins, Jun 8, 2005
    #2
    1. Advertising

  3. Joe Van Dyk

    Joe Van Dyk Guest

    On 6/7/05, Joe Van Dyk <> wrote:
    > Hi,
    >=20
    > Anyone have any tips for writing GUIs in Ruby (using Tk, for example)
    > using a TDD approach?
    >=20
    > 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.
    >=20
    > 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.
    >=20
    > 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.
    >=20
    > Thanks,
    > Joe
    >=20


    Here's a very simple example of a quick UI app that's unit tested.=20
    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.



    require 'tk'
    require 'test/unit'

    class App
    attr_accessor :sum, :inc_button, :display_button, :power_2_button

    def initialize
    @sum =3D 0

    root =3D TkRoot.new :title =3D> 'my app', :geometry =3D> '300x300'

    @inc_button =3D TkButton.new(root,=20
    :text =3D> "Increment!",
    :command =3D> proc { inc }
    )
    @inc_button.pack :expand =3D> true=20

    @power_2_button =3D TkButton.new(root,
    :text =3D> "Power of 2",
    :command =3D> proc { power2 }
    )
    @power_2_button.pack :expand =3D> true
    end

    def inc
    @sum +=3D 1
    display
    end

    def power2
    @sum *=3D @sum
    display
    end

    def display
    puts @sum
    end
    end


    class TestApp < Test::Unit::TestCase
    def testInc
    app =3D App.new

    assert_equal 0, app.sum

    app.inc_button.invoke
    assert_equal 1, app.sum

    app.inc_button.invoke
    assert_equal 2, app.sum
    end

    def testPower2
    app =3D App.new

    assert_equal 0, app.sum
    =20
    app.power_2_button.invoke
    assert_equal 0, app.sum

    app.inc_button.invoke
    assert_equal 1, app.sum

    app.power_2_button.invoke
    assert_equal 1, app.sum

    app.inc_button.invoke
    assert_equal 2, app.sum

    app.power_2_button.invoke
    app.power_2_button.invoke
    assert_equal 16, app.sum
    end
    end

    if ARGV[0] !=3D 'test'
    App.new
    Tk.mainloop
    exit
    end
     
    Joe Van Dyk, Jun 8, 2005
    #3
  4. Joe Van Dyk

    Joe Van Dyk Guest

    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
    > >

    >=20
    > Here's a very simple example of a quick UI app that's unit tested.
    > Comments appreciated.
    >=20
    > 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.
    >=20
    > 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,=20
    :eek:utput_label

    def initialize
    @sum =3D TkVariable.new
    @sum.value =3D 0

    root =3D TkRoot.new :title =3D> 'my app'=20

    @inc_button =3D TkButton.new root
    @inc_button.text =3D "Increment"
    @inc_button.command =3D proc { inc }
    @inc_button.pack :expand =3D> true

    @power_2_button =3D TkButton.new(root)
    @power_2_button.text =3D "Power of 2"
    @power_2_button.command =3D proc { power2 }
    @power_2_button.pack :expand =3D> true

    description_label =3D TkLabel.new
    description_label.text =3D "Result:"
    description_label.pack :expand =3D> true
    @output_label =3D TkLabel.new
    @output_label.textvariable =3D @sum
    @output_label.pack :expand =3D> true
    end

    def inc
    @sum.value =3D @sum.value.to_i + 1
    end

    def power2
    @sum.value =3D @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 =3D 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 =3D 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] !=3D 'test'
    App.new
    Tk.mainloop
    exit
    end
     
    Joe Van Dyk, Jun 8, 2005
    #4
  5. Joe Van Dyk

    Joe Van Dyk Guest

    On 6/8/05, Joe Van Dyk <> wrote:
    > 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?


    Tk question: How can I tell, via code, if a button is actually being
    displayed on the screen?

    Say buttons are being created based on data from a configuration file.
    If I have a method that reads the config file and generates buttons,
    how can I make sure those buttons are actually going to be displayed
    on the screen?

    I just ran into this problem when I forgot to 'pack' some buttons,
    where 'packing' in Tk makes them visible/active on the screen. But I
    don't know how to test for that.
     
    Joe Van Dyk, Jun 8, 2005
    #5
  6. Joe Van Dyk wrote:

    >Tk question: How can I tell, via code, if a button is actually being
    >displayed on the screen?
    >
    >

    Look at my original response to you. Your unit tests don't need to test
    that Tk is doing its job (hopefully the Tk people are doing that, but
    seconding that, maybe your functional end-to-end tests are). Your unit
    tests only need to test that you are making the right calls to the right
    Tk methods.

    Devin
     
    Devin Mullins, Jun 9, 2005
    #6
  7. From: Joe Van Dyk <>
    Subject: Re: Test-Driven Development in GUIs
    Date: Thu, 9 Jun 2005 07:59:31 +0900
    Message-ID: <>
    > Tk question: How can I tell, via code, if a button is actually being
    > displayed on the screen?


    Does TkWinfo.mapped?(win) or TkWindow#winfo_mapped? satisfy you?
    --
    Hidetoshi NAGAI ()
     
    Hidetoshi NAGAI, Jun 9, 2005
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Yan-Hong Huang[MSFT]
    Replies:
    0
    Views:
    415
    Yan-Hong Huang[MSFT]
    Oct 15, 2003
  2. Sasha
    Replies:
    3
    Views:
    429
    Scott Allen
    Mar 2, 2005
  3. Michael P Smith

    Test-driven Development in C#

    Michael P Smith, Apr 24, 2004, in forum: C Programming
    Replies:
    4
    Views:
    652
    Dan Pop
    Apr 26, 2004
  4. Steven D'Aprano

    Test-driven development of random algorithms

    Steven D'Aprano, Nov 14, 2006, in forum: Python
    Replies:
    2
    Views:
    273
    Ben Finney
    Nov 14, 2006
  5. Shaguf
    Replies:
    0
    Views:
    823
    Shaguf
    Nov 28, 2008
Loading...

Share This Page