A Lesson Relearned
After a couple of days of developing this library, it was time for a demo. Showing the testers how the library worked using the xUnit framework within my IDE was a snap. They had a lot of questions, most of which could be answered by walking them through a particular test I had written. One question threw me off, though: "This looks fine in your development environment, but how will it work when I use it with my tests?" It dawned on me that I had been so enamored with my automated unit tests and so busy programming that I had forgotten to run any functional tests. Oops.
I wasn’t sure what would happen, so I wrote some code that would rely on this library (as the testers would when using it), gathered some real production data that was used by the testers, and ran a functional test. It failed. My interface into the library didn’t work very well. It worked fine for the xUnit framework with my mocked-up data, but didn’t stand up to real-world use. My own words came back to haunt me: "Don’t rely completely on automated unit tests; be sure to run functional tests in a system as close to production as possible." The proof of the degree of testability in a design can only be known by actually testing after development, by investigating the results of the tests, and by adjusting those tests based on the test results.
I needed to do a bit of redesign for functional testability, so I created a suite of functional tests. They took a lot longer to run, but my automated unit tests provided a safety net so I could make changes with ease. Shortly I was able to work the code so that the automated unit tests all passed, as did the functional tests. It now had the added bonus of being testable in both situations, and was ready for a production trial. I demonstrated the new functional tests for the testers, and added application programming interface (API) documentation to the library so testers could start using it. I felt sheepish that I had become so in love with my "green bar" that I forgot I was a tester for a while.
Testing too much in one context (in my case, the code context), can skew our views. There are many contexts in which we can test, and all help us get a different view of the software and provide useful information. Through this process, I came to realize how easy it is to develop a false sense of security when the focus of testing is too narrow. I had quickly fallen into a trap of narrow testing thinking, and once again had learned a lesson.
Once the library was ready for production, I paired with a tester who helped me run through some manual functional tests. When we were satisfied with the results, I released the test library for use by the rest of the team. I also released the tests internally—both the TDD-derived automated unit tests and the functional tests. Internal users could then use the tests as product documentation to get up to speed using the library, and use them as tests in the test environment if they needed to change the library or verify a change in the environment.