Tabbedimages is a simple image viewer. We are going to add drag and drop feature to it.
I start with a requirement, which I analyze and spike for a working solution. Based on the analysis I create a user story and an automated acceptance test. The acceptance test "drives" me when I'll add unit tests and the production code.
- Requirement
- tabbedimages is a simple image viewer.
- We want to add a new feature to tabbedimages.
- Title.
- 'Drag&drop support'.
- TIP: It's good to have a short title for a user story.
- Analysis: let's list things to worry about:
- Single image files
- Multiple image files
- Directories
- Non-image files
- Already open image.
- Spiking
- TIP: This part should give us better understanding of the problem
- If we're sure how to implement the new feature we can skip this step.
- tabbedimages is implemented using IronPython and Windows Forms.
- The code is availalable here.
- Google for 'drag and drop windowsforms' and see some code examples.
- Check out the fresh version of tabbedimages.
- Try to add the required feature to our code base (without tests).
- Discover that Windows Forms has support for DragDropEffect.
- Which displays a 'plus' sign if the thing that we're trying to drag is acceptable.
- Add the DragDropEffect to the list of things to worry about.
- User story:
- Marten wants to drag and drop his images from his desktop to tabbedimages.
- He starts tabbedimages.
- He then drags the 'Faye001.jpg' file over the application.
- The plus sign appears.
- He drops it.
- A new tab is created with a label saying 'Faye001.jpg'
- 'She's cute' he thinks
- Marten realizes that there are more Faye's pictures.
- He drags 'Faye001.jpg' (again) and 'Faye002.jpg'.
- He drops them.
- Two new tabs are created.
- He drags and drops readme.txt file.
- The message box appears saying 'readme.txt doesn't appear to be a valid image file'
- He quits tabbedimages.
- Functional test:
- Write the ideal code (DSL-like) that follows the user story steps:
marten.starts()
he.asserts_number_of_tabs(0)
he.drags('Faye001.jpg')
assert shows_plus()
he.drops('Faye001.jpg')
he.asserts_number_of_tabs(1)
he.asserts_tab_labels(['Faye001.jpg'])
fayes_pictures = ['Faye001.jpg', 'Faye002.jpg']
marten.drags_and_drops(fayes_pictures)
marten.drops(fayes_pictures)
he.asserts_number_of_tabs(3)
he.asserts_tab_labels(['Faye001.jpg', Faye001.jpg', Faye002.jpg'])
he.drags_and_drops('readme.txt')
he.sees_message_box("readme.txt doesn't appear to be a valid image file")
he.quits()
- Implementation
- Run the Functional Test (FT).
- Whenever FT fails or you can think of any edge cases not covered by FT:
- Write appropriate Unit Test that reflects the problem.
- Add the implementation to fix the problem.