All atomic-powered posts filed in “Test Driven Development”:



Information Radiators

stoplight

For a business that by definition occupies a highly technical domain, we have some relatively low-tech means of conveying information internally. Sure we e-mail, Twitter, Yammer, and even Skype with each other on a regular basis, but we also make use of yarn, note cards, cork boards, and old traffic equipment. I’m talking about our information radiators, objects around our office that align the team by sharing important information in a fun and hard-to-miss way.

Read the rest of this entry

Testing terminology

Working with some new customers this year has given me fresh perspective on how confusing the terminology of the testing world can be. I think terms and definitions matters a lot, and not just because I’m a recovering academic. Several times recently I’ve found myself in a conversation taking a position in apparent opposition to my companion, only to eventually determine that we were in fact talking about the same thing. Or we might have been using the same words, but actually meaning very different things. I don’t know that the testing world is any more inconsistent in their terms than other technical fields, but it sure seems like it sometimes.

Read the rest of this entry

Harvard Business Review motivates TDD

In the article What Really Motivates Workers, the January-February 2010 issue of Harvard Business Review reports on a multi-year study of top performance motivators. Between these five contenders:
  • Instrumental support
  • Progress
  • Interpersonal support
  • Collaboration
  • Important work

progress was the top motivator by a large margin.

(Unfortunately, when the researchers surveyed 600 managers they found that most of them believed that “recognition for good work” was the top motivational factor.)

I think the study explains why test-driven development (TDD) is self-sustaining once mastered. Large software projects done in traditional fashion may go for months without finishing or delivering anything. That’s a hard situation in which to see progress, and hence un-motivating. The same project done with TDD results in a smaller system becoming functional more quickly, daily progress as you integrate your working code and tests with others, and even hourly progress in the form of the “green bar” of passing tests. Progress is more visible and more reliably and regularly experienced.

The author also found that the most de-motivating days were those where people experienced the opposite of progress: a setback. Anyone who’s worked on a body of un-tested legacy code knows how common it is to make a change and break something. Setbacks are a de-motivating experience made more common by the lack of any test control.

Developers are motivated by the progress TDD brings and shows them.

Faster, better, cheaper! TDD wins in a simple experiment

Earlier this year I had the unusual opportunity to work on a project with another developer (I’ll call him Dave – not his real name) in which each of us was free to choose our own method of application development.

This is certainly not an ideal situation. At first I considered following the client’s (Dave’s company) development methods just for consistency, but I ultimately decided to follow TDD for my portions of the project for several reasons:

Read the rest of this entry

Testing Swing applications using JRuby

Demetrius Nunes recently posted about his Swinger library to the JRuby mailing list. Swinger uses Cucumber and Jemmy to provide a test harness for automating Swing tests.

I responded to Demetrius letting him know how great it is to hear others are interested in automating Swing testing. We’ve been using a combination of FEST and Ruby helpers specific to our own Swing applications. As Demetrius notes, Swing tests can be frustratingly brittle, but they are still well worth the investment. Swinger looks like it is both extensible and can help alleviate some Swing testing pain.

You can check out my response here and the entire discussion here.

Nesting RSpec Describes

Like many people at AO, I have come to enjoy testing code in Jay Fields' one assertion per test style.

This style is great for testing because it clearly establishes intent for each test. This point is invaluable when another developer either inherits your code, or you revisit it at some point in the future. The main problem with this style is the need to create stubs for all the calls in the describe's before block, or resort to using stub_everything for all your mock objects. These are both fine solutions for simple code, but as soon as the logic encounters a condition you may be setting yourself up for potential testing bugs, and difficulty when you add new logic.

One way to avoid this problem is to leverage the power of rspec, and use nested describe blocks for each condition statement. This helps limit the before block for each describe to only define the stubs for that condition block. This is helpful because it prevents the tester from accidentally defining a stubbed expectation for something that should not happen. It also creates a nice placeholder for adding logic into the code in the future.

The following example shows how nesting rspec describes works. It is important to note that the branch that contains the most logic should be encapsulated in the sub-describe.

Example Source Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Example 
  def run(director, runner)
    runner.prepare
    if director.go?
      runner.run
      if runner.complete?
        director.stop
      end
      runner.stop
    end
    runner.finish
  end
end

Example Test Code with nesting describes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
describe Example do
  before do
    @target = Example.new
  end
  
  describe '#run' do
    before do
      @director = mock
      @runner = mock
      
      @runner.stubs(:prepare)
      @director.stubs(:go?).returns false
      @runner.stubs(:finish)
    end
    
    it "should prepare the runner" do
      @runner.expects(:prepare)
      @target.run @director, @runner
    end
    
    it "should check the director" do
      @director.expects(:go?).returns false
      @target.run @director, @runner
    end
    
    describe 'director returns true for go' do
      before do
        @director.stubs(:go?).returns true # redefine
        @runner.stubs(:run) 
        @runner.stubs(:complete?).returns false
        @runner.stubs(:stop)
      end
      
      it "should run the runner" do
        @runner.expects(:run)
        @target.run @director, @runner
      end
      
      it "should check if the runner is complete" do
        @runner.expects(:complete?).returns false
        @target.run @director, @runner
      end
      
      describe 'runner returns true for complete' do
        before do
          @runner.stubs(:complete?).returns true # redefine
        end
        
        it "should stop the director" do
          @director.expects(:stop)
          @target.run @director, @runner
        end
      end
      
      it "should stop the runner" do
        @runner.expects(:stop)
        @target.run @director, @runner
      end
    end
    
    it "should finish the runner" do
      @runner.expects(:finish)
      @target.run @director, @runner
    end
    
  end
end

I realize the test code gets a bit long, but it is very easy to understand and extend. Also, nesting on conditional breaks creates an easy framework to follow when writing test code.

Building scaleable web apps

Web entrepreneurs, at least the ones we’re experienced with helping, have limited budgets. They’re also inherently optimistic people, believe deeply in their idea, and want confidence that their development team will build something that handles the heavy traffic that success will bring. The answer they want to hear is usually something like, “we design scaleability in right from the start”. Our experience tells us there’s a better way.

Read the rest of this entry

Using Tests for Requirements Management

Everybody who gets excited about requirements management and documentation – raise your hand. Okay. Thank you. You’re free to go. For those left – you can mate automated tests with a bit of convention and scripting magic to simplify your requirements management life. Here’s how.

Read the rest of this entry

Saved by Tests - Upgrading to Rails 2.2.2

Two weeks ago, I upgraded a project from rails 2.0.2 to 2.2.2. I had done some polymorphic associations, and I needed more powerful eager loading to prevent N+1 queries. The latest version of rails happens to meet my needs perfectly.

I told the customer that this work needed to be done and that it might take a few days to do it right, as it's a large project and depends on a large number of gems and plugins. The customer was very reasonable and said if it had to be done, then we'd take the time to do it right. So I did the upgrade.

Read the rest of this entry

Testing Ensemble Productions

This article is a follow-up to Test Automation in InterSystems Cache and Ensemble. An Ensemble production is a configuration of objects that interact with each other and perform different tasks. A typical HL7 production is composed of inbound services, message routing processes, transformations, and outbound operations.

Typically productions are tested manually by observing desired outcomes. However, manual tests do not exercise individual components of the system and do not lend themselves to automated regression testing. We at Atomic Object have had great success breaking up a production into its components and building automated functional and unit tests for these components.

Read the rest of this entry

Testing and Legacy Code, A Primer

In the last few weeks, customers and potential clients have asked me on several occasions how Test-Driven Development relates to legacy code (incidentally, one fitting definition for legacy code is code having no test suite).

As much as we all might like to throw out legacy code (especially when it’s craptacular) and “do it right”, that’s often an entirely impractical option or just a plain dumb thing to do. Reality is that there’s no magical formula or one-size-fits-all procedure for dealing with testing and legacy code. Each case is unique and requires a thoughtful, responsible approach. That said, I offer here guidelines toward tackling the challenge in a thoughtful, responsible way.

Read the rest of this entry

Test Automation in InterSystems Cache and Ensemble

Atomic Object has been providing development and consulting services for a company in the healthcare industry. We’ll refer to this company as DoctorsInc hereinafter. Our primary focus was to bring agile project management and TDD practices to DoctorsInc’s development process. The group that we worked with at DoctorsInc uses a powerful ETL tool called Ensemble.

Ensemble is a product developed by a company called InterSystems that sits on top of another product called Cache. Cache is an integrated development platform and OODB that provides a powerful set of tools for development, database management, and much more.

Read the rest of this entry

Greasemonkey On My Back!

Last week I was creating a web form that generated a few emails upon submission. I was dropping my code into a client's existing site that was developed by a different company. The existing code had no tests and looked like it was being pushed right to production via Dreamweaver or something similar. It was also one of those PHP, MVC-all-in-the-View situations. Hey, it's all party though... right?

I decided to manually test the form because the scope was small, there was no professional way to deploy the entire site, and there was no suite of existing regression tests that could be run. I still needed a way to iterate quickly while conducting manual tests.

Greasemonkey saved the day! I was able to write a quick script that filled out the form with some baseline data. I could switch some of the data manually and check the results quickly. I was able to use the same script in production. The experience reminded me of writing automated Selenium or Celerity integration tests and prompted me to think more about utilizing Greasemonkey as a QA tool.

--UPDATE--

Kristofer commented that a brief example would be useful.

Using Firefox, I got the Greasemonkey add-on. Once installed, I browsed to the form I was developing and navigated the Firefox menu: Tools -> Greasemonky -> New User Script... Then I wrote the Javascript that would fill in the form. I added a listener for the window onload event and within the callback I accessed the dom and updated the form values. It looked similar to this:

1
2
3
4
5
window.addEventListener("load", function(event) {
  document.getElementById("name").value = "Name";
  document.getElementById("email_address").value = "test@example.com";
  document.getElementById("address1").value = "123 Cranberry";
}, false); 

I had to create HTML and Mouse Event objects to invoke click and change events on some of the form elements that had their own event handlers. The Greasemonkey user script manager window allowed me to associate the script with my development and production deployments.

This was some really simple stuff that proved to be very helpful.

Embedded Testing Tool Goodness Now Available

It’s been a long time coming. Funny how real work can get in the way.

Unity and CMock began life as quick and dirty little tools Atomic Object used internally for our first client embedded projects. CException was born in our most recent X-Rite work. Our colleague at X-Rite, Mark Vander Voord, made significant contributions to all three – especially CException since he wrote the whole darn thing.

iPhone Development Experience

I had the opportunity to attend Apple's World Wide Developer Conference this past June. I attended the conference to learn about and gain experience in iPhone development. Most of my time was spent in the iPhone Lab and iPhone development presentations and sessions. I thought most the presentations were informative and well presented and I came away with a lot.

My only complaint is that Apple would not talk about or even acknowledge the more complex areas of sample code in their presentations. It was obvious Apple was focusing on making iPhone development look very easy through and through. And compared to other mobile platforms it is easier. However I wish they had spent some time going into the more complex, non-apple abstracted code that actually takes some time and thought.

The development experience is a good one. The language (Objective C), iPhone SDK and the development tools are well done. Objective C is a powerful object oriented language and the iPhone SDK is well abstracted and easy to use. If you need access to the more low-level API's they are readily available. Interface Builder is spectacular and it puts other interface/view building applications to shame. Xcode is still way behind other IDEs but it is very usable nonetheless. Their performance and debugging tools are excellent. Even when your code is well formed and well tested you have the potential to have memory leaks, and their memory leak detection tool is great for that kind of problem.

From a professional development standpoint the platform is ready to go. A developer can test drive their code using OCMock and OCUnit. If you prefer a different testing platform I recommend looking into rbiphonetest.

I was able to successfully create an iPhone application using Atomic Object's Presenter First style of development. However, bootstrapping the application becomes problematic when the application uses a great deal of composition. It would be nice if a dependency injection framework existed and was available for iPhone development. However, it is possible to use Interface Builder to instantiate all of the singletons in the system and inject them, which could be an acceptable alternative.