SWTBot and Eclipse 3.4 (Ganymede)
SWTBot has so been supporting Eclipse Ganymede since the last 2+ years before it moved to eclipse.org.
Ganymede is now almost 2 years old and the last bug fix release was in Feb 2009.
There has been a Galileo release of Eclipse in the Summer of 2009, and there is a new release Helios coming up the horizon.
Given this situation, it is very difficult to continue to provide a light weight testing tool that works across 3 different versions of eclipse on 4 different platforms linux, windows and macosx(carbon/cocoa) while backporting APIs that only work on newer eclipse versions.
In light of this, I’m considering dropping support for eclipse 3.4 for future releases. I’m happy to assist anyone wanting to contribute efforts towards maintaining a release of SWTBot for Ganymede.
The v2.0.0.568 of SWTBot made last night would be the last that supports Ganymede.
Know your users’ brains
It is important to know who your users are when you are in the business of building anything. Building things is expensive. Software or otherwise.
My mom would rather use a mac over a gentoo. A systems admin would rather use redhat over a mac on a production machine.
It is also important to say “NO” to people who are not your users. Almost all software at eclipse.org are frameworks, tools and app servers written primarily for developers.
The way software and API is designed for the developer is different from how it’s developed for the non-developer (most of the times). SWTBot was originally and still is primarily a test-automation tool for use by QAs to automate test cases. The APIs are designed to be extremely intuitive, simple and easy to extend by QAs by merely looking at examples and not having to read API documentation.
Some context is in order if you haven’t had the opportunity to work closely with QAs before. Most QAs I’ve met understand customer requirements, understand the software and what the customers want out of it. I like to treat them as end users of the buggy software I build. They may not understand SWT threading, the eclipse ui and platform, OSGi and how TCP packets travel across the corporate firewall over to a load distributor in front of a cloud hosted at a datacenter on the other side of the continent. Try explaining a “org.eclipse.swt.SWTException: Invalid thread access” to a QA and you’ll get interesting looks.
QAs are good at finding bugs in whatever software they are testing. Testing all of the software is time consuming, not to mention testing backward compatibility with older software. Nobody likes clicking around the same navigation path in the UI all the time.
QAs like exploring interesting ways to use the software and ensure that it works consistently as software evolves over time. The traditional favorites have been the ‘heavy weight’ automation tools like HP’s QTP, IBM’s Rational Robot, Borland’s SilkTest and the open source ‘light weight’ tools like selenium, sahi, and a lot others.
Each of these tools has its advantages and disadvantages. One of the most powerful features of each of these toolchains is the ability to author scripts in a dynamic language. The commercial vendors use vbscript or some other variant of the language, and provide some forms of integration with defect tracking tools. The open source tools are primarily light weight, use the languages like javascript, ruby, python and don’t integrate much with anything but your IDE and things like ant or rake.
The end goal is to make SWTBot an extremely good, open source, light weight tool for QAs to automate tests, and be just about useful for developers to write simple test cases with and not something in between that neither of them like.
As part of evolving SWTBot APIs we need to ensure that we stay true to our goal. This sometimes means saying NO to feature requests and even patches from developers if it hurts the non-developers.
Tell, Don’t Ask – Part 2
Objects exposing behavior, not state
Controlling complexity of your codebase by limiting what state your objects expose
The more objects that can see and change states on other objects, the more complex your system. Objects returning a boolean mean that someone calling that method will use an if branch, returning an integer would mean someone using if/else or switch/case. Returning objects would mean introspeting that returned object to invoke something else on it. This increases coupling between classes, makes code hard to read and test.
My class has 3 friends, I talk to my friends’ friends. My friends are difficult to mock, therefore mocking sucks…
… well, yeah!
Testing procedural code is hard. Testing such code generally involves setting up “data” and asserting on state of objects. Tell Don’t Ask code on the other hand is easier to test since you’re not testing state. Also notice how DI makes things simpler to test.
void testOwnerCanFeedDog(){
Dog dog = new Dog();
// have to create a mouth since owner calls dog.getMouth() to feed it
Mouth mouth = new Mouth();
dog.setMouth(mouth);
PetOwner owner = new PetOwner();
owner.setDog(dog);
owner.feedDog(food);
// verify that the dog gets the food (well the mouth, actually)
assertEquals(food, mouth.getFood());
}
void testOwnerCanFeedDog(){
Dog dog = mock(Dog.class);
PetOwner owner = new PetOwner(dog);
owner.feed(food);
// verify that the dog gets the food
verify(dog).feed(food);
}
Without Dependency Injection, testing is quite difficult; without Tell Don’t Ask, testing is almost always impossible. Put together, things are separated, testing is simplified.
Tell, Don’t Ask – Part 1
I spend more time reading code than writing it. I therefore like code that is readable. Rarely do I like to read code that is verbose and does too much orchestration in order to do something that is orthognal to what I’m looking for.
Code is easier to read and maintain when objects are written in a Tell Don’t Ask.
“Tell, Don’t Ask” is a style of programming where anObject tells anotherObject to doSomething(), rather than asking anotherObject to getSomeValue() and then makeADecision().
Code that does violates this this is more procedural than it is object oriented. In the procedural world code is written to fetch some data (or state) and then make a decision or perform some action. Procedural programming “pulls data” into the logic to get things done.
In object oriented programming, we do the opposite — have objects do something for you instead of you doing it yourself. Don’t overdo this too much, someone still has to do the real work though
Identifying places where you may tell instead of ask:
class PetOwner{
void feedDog(Food food){
if(getDog().isHungry()){
dog.getMouth().putFood(food);
}
}
}
This can instead be written as:
class PetOwner{
void feedDog(Food food){
dog.feed(food);
}
}
class Dog{
void feed(Food food){
if (iAmHungry()){
// consume food
}
}
}
Notice how the PetOwner does not know (or care to know) about the fact that the dog has a mouth.
Code Coverage And Functional Tests
I am often asked this rather perilous question:
How do I view code coverage for my functional tests?
Short answer:
Here’s how…. However, use it only for figuring out what functionality is not covered, not as a workaround for not having enough unit and integrations.
Having to use functional tests to determine percentage of code coverage is IMO a bad smell, avoid as much as possible.