| Exploring Solution Spaces © Copyright 2003-2006, by C. Keith Ray | ||||||||||||||||||||||||
|
Archives
Subscribe |
2008.Jun.09 Mon
Don't Let Your Programmer Tests Turn Into Fairy Tales
Maybe you start out with:
void testLittleRedRidingHood()
{
LittleGirl child = new LittleRedRidingHood();
assertTrue(child.hasHood());
}
but then you add something more
void testLittleRedRidingHood()
{
LittleGirl child = new LittleRedRidingHood();
assertTrue(child.hasHood());
assertTrue(child.hasBasket());
Basket basket = child.getBasket();
assertTrue(basket.hasGoodies());
// we're kind of drifting away from LittleRedRidingHood now...
}
and more
void testLittleRedRidingHood()
{
LittleGirl child = new LittleRedRidingHood();
assertTrue(child.hasHood());
assertTrue(child.hasBasket());
Basket basket = child.getBasket();
assertTrue(basket.hasGoodies());
Wolf wolf = new BigBadWolf();
// now we're really going astray...
assertTrue(wolf.hasBigTeeth());
}
If your programmer test (a.k.a. "unit test") is telling a long story, it's probably is too long, not focused enough. Step Into Your Agile Groove With Industrial Logic’s Greatest Hits 2008.Feb.16 Sat
Spammers are using my email address
My email address used in this blog (k e i t h r a y @ m a c . c o m, not that anti-spam measures are going to help anymore) is being used as the return-address by spammers, so my inbox is filling up with automated spam rejection messages. I am not the one trying to sell you male enhancement drugs or devices, other "discounted" drugs, nor Florida real estate. I hardly ever use that email address anymore, so I suppose I'll be shifting over to another address and closing that one down, sooner or later. Frakking spamers. :-( 2008.Jan.27 Sun
Making a Waterfall Project Succeed
Many moths ago, I read an informative and often amusing book called It Sounded Good When We Started: A Project Manager's Guide to Working with People on Projects by Roy O'Bryan and Dwayne Phillips about (among other things) a waterfall hardware/software project whose management got disconnected from reality and the author had to take over project management to get the project back on track. Many of the techniques he used (putting the project plan on the wall as a frequently-updated information radiator, low-overhead daily updating of current and near-future planned tasks, avoiding delays between engineering activities and quality assurance activities) are also used in Agile projects. I think of Agile development methods as including lightweight ways of incorporating feedback into the process. It turns out making a Waterfall project successful requires the same thing: frequent, timely feedback. Step Into Your Agile Groove With Industrial Logic’s Greatest Hits 2007.Dec.08 Sat
Jame Shore on What's the value of functional testing?
James Shore lightening talk (video) transcript quotes:
Check it out
Elisabeth Hendrickson on Why Automated Acceptance Tests are Crucial
Elisabeth Hendrickson’s lightening talk (video). 2007.Nov.26 Mon
Industrial Logic's Greatest Hits
Industrial Logic has a new home page, where you can browse and purchase eLearning products for C++, Java, and C# on the subjects of Code Smells, Refactoring, and Microtesting. The front page also lets you Take a Tour and experience the Welcome Album, which includes blooper videos. Joshua Kerievsky, Mike Hill, and Gil Broza are the authors of this self-paced training material, as well as the instructors who use the same materials in Industrial Logic's in-person workshops. 2007.Nov.25 Sun
Return of the Blog: Pairwise testing
I haven't been blogging much lately, but it's time to spill. Miscellaneous subjects follow. Via Michael Bolton, a paper (pdf) "Pairwise Testing: A Best Practice That Isn't", by James Bach and Patrick J. Schroeder Quotes: 2007.Oct.12 Fri
What's the point of tests that pass all the time?
When I'm doing Test Driven Development, my tests (almost) always fail - at least once. This is because I write a test and run it before I write the code to make the test pass. It should fail because the functionality isn't implemented yet. I could design my code without using the tests to guide me, but then I find that I spend a lot of time debugging manually, and afterwards, I don't have tests to find regressions. I define regressions as bugs for already-implemented features which can get injected into the code during refactoring or when adding new features. So the tests in TDD are serving two purposes: guiding my design, and guarding against regressions. However, I don't check into source-code-control when tests are failing, and I hope my team-mates do the same thing. So from the viewpoint of the team's continuous integration server, the programmer tests used for TDD should never fail. Sometimes they do, because we make mistakes: we forget to check in something, or the tests are poorly written -- for example, a test might be accessing a live external server that isn't running all the time, or has inconsistent time-outs or other 'flaky' behavior. The skills for TDD and writing reliable tests are more subtle than they ways of wizards, but they can be learned. [I've been watching Lord of Rings again.] 2007.Oct.05 Fri"splogs" is inspired to use 'const' more in C++ after exposure to Haskell. Quote:
An anonymous commenter responded:
Consider this bit of code:
Results aFunction(SomeClass& anObject)
{
someval = anObject.SomeMethod();
// later...
someotherval = anObject.SomeOtherMethod();
// etc.
return results;
}
Given that anObject is not const, you'd have to assume that SomeMethod and SomeOtherMethod could be modifying the state of the object. If you changed the order of calls, or called one of those methods more than once, you could break the desired behavior. The only way to know for sure would be to look at the source-code and/or documentation for SomeClass's methods. Now with const-ness:
Results aFunction(const SomeClass& anObject)
{
someval = anObject.SomeMethod();
// later...
someotherval = anObject.SomeOtherMethod();
// etc.
return results;
}
The simple act of declaring anObject to be const also implies that SomeMethod and SomeOtherMethod are const methods. (The compiler will complain if that's not true). This assumes the programmer for SomeClass was following the rules (that is, he's not 'faking' const-ness) and SomeClass isn't modifying some external state that we care about. In this case with a const reference and const methods, we could be pretty sure that we could change the order of method calls, and the number of times the methods are called, with no effect on the correct behavior. Unfortunately, even with 'const' we can't always be sure the behavior is correct, so writing micro-tests helps enforce the intended behavior. A test like...
TEST(aFunctionDoesWhatWeWant)
{
SomeClass anObject; // set up how we want
Results fResults = aFunction(anObject);
AssertEqual(expectedState, anObject.GetState());
AssertEqual(expectedResults, fResults);
}
... would help us verify that the following changes are okay, if it still passes after changing the order and number of calls.
Results aFunction(const SomeClass& anObject)
{
someval = anObject.SomeMethod();
someotherval = anObject.SomeOtherMethod();
// later...
someotherval2 = anObject.SomeOtherMethod();
someval2 = anObject.SomeMethod();
// etc.
return results;
}
Declaring a function parameter const also helps tell other programmers that the function isn't going to try to change the object's value. Tests will help document the function's desired behavior. 2007.Sep.20 Thu• Purity metric: the ratio of pure virtual methods over the total number of methods of a class. Purity of 1.0 is good for an abstract base class. Purity of 0.1 might be ok for a class implementing the Template Method Design Pattern. Purity of 0.5 is likely to be bad because the class is going to be confusing. It is likely to be an abuser of "inheritance for implementation". Note that Template Method relies on subclassing from a class with a partially-concrete implementation, and might be better replaced by the something like the Strategy Design Pattern, which has a concrete class parameterized by injection of pluggable strategy objects (whose parent class is purely abstract). • Public Interface metric: the ratio of public methods over the total number of methods of a class. A measure of 1.0 is probably good: all public methods, and no private methods (at least it's testable). A Public Interface number of 0.1 is likely to be bad - the class is consisting of mostly private or protected methods, and thus hard to test. A low number is a sign of the Iceberg Class , often indicating that the class is too large and should be broken up into several smaller, collaborating classes (after the break-up, maybe only one class is still part of the public API, but the other classes who now have public methods would be testable.) • Static Cling metric: the number of static variables in a class, including static variables in the class's implementation file, whether file-scope or function-scope. • Anti-Polymorphic metric: number of static functions and non-virtual functions in a class, plus the number of file-local functions in the class's implementation file. |
|||||||||||||||||||||||