I realised after looking at what I’ve blogged so far that I haven’t written much about actual testing, my first discipline. So, today I’ll provide an insight into how we develop and test software in our department. We have adopted the stance that having a role to find defects is wasteful and effort should be made to ensure such defects are not written (more on this soon). Thus, we do not have testers. However, our developers know how to test; developing with a focus on quality throughout underpins our process.
I’ve mentioned previously about baking-in quality and not having developers throw code over a wall to testers. I also mentioned automating the execution of acceptance criteria, written to define features, in order to aid development today and form regression tests tomorrow. Today I’ll give a very brief overview of each stage (most of which may sound obvious to anyone practicing agile); I’ll go over each stage in greater detail in later posts (my promise to you).
Naturally, the following outline is within the context of our team but there are variations to practices and toolsets that we use. These depend on what we’re working on (web/desktop) to appetite for risk (safety critical/profit).
Overall: Baking quality in with XP, scrum and lean principles
My team consists of 3 developers and myself (I am considered a developer, albeit not as good as the others, but with a better fault model). Everyone on the team is concerned with not only assuring quality in what we deliver, but making it visible to ourselves and the business.
We work in an agile manner, iterating through development with extreme programming practices and Behaviour Driven Development. Facilitating our relationship with the business is Scrum and we utilise kanban principles and systems thinking to maintain a speedy throughput of high-quality work. This mixture allows us to communicate effectively, develop the correct features properly and continuously deploy our work when it is complete, thus maximising business value. I should also mention that we are fortunate enough to have our business people/customer sat across from us.
From start to end: Starting with a User Story & Acceptance Criteria
I have written about user stories, acceptance criteria and how we improved the clarity of them in the teams within our department. Our stories describe a small, releasable piece of functionality and are supported with thorough acceptance criteria, (the level of thoroughness depends on the context and risk attached). The cognitive effort put into traditional end-of-cycle testing is used upfront to obtain these criteria. By anticipating and exploring what we should deliver before we start coding, we have a development goal to aim towards and know we are done once these are met.
Automating Acceptance Criteria
Our acceptance criteria are our acceptance tests, (like a Möbius strip). We automate our acceptance tests in one of the following two ways.
If the feature relates to user interaction through the front end, e.g. pages on a website, we write the acceptance criteria in Cucumber. These are in plain text files in a given-when-then format. At the top level, Cucumber runs Watir, which manipulates the browser. We develop with BDD to make the Cucumber acceptance tests turn green as they execute.
If the feature relates to more data-driven/domain logic then we represent the acceptance tests in Fitnesse. Fitnesse uses fixtures to interact directly with domain objects. In their simplest form, tests are written in Excel-like tables within a wiki, (which helps when collaborating with business people) and turn green when the system under test returns the expected output.
BDD and Pairing With Awesome Developers.
Practicing BDD allows us to deliver correctly working, tested software. Firstly, a failing acceptance test scenario drives development. Dropping down into the code, red-green-refactor cycles with nUnit specs help design, document and test internal domain objects. These unit test cycles are repeated until the inital failing acceptance test that we set out to pass is doing so.
When coding we pair-programme (using the pomodoro technique). Alistair Cockburn and Laurie Williams’ paper “The Costs and Benefits of Pair Programming” describes the many advantages to pair programming.
No Testers, Testing or Inspection (being lean).
Huh, no testers?! Without testers or a QA team there is no wall over which work can be thrown and the responsibility for quality absolved. We as developers are responsible for delivering quality, therefore we focus on quality. This department-wide stance is achieved by solid direction from department heads, like our Development Manager.
The inspection typically carried out end-of-cycle only yields bugs that were low severity and of no real impact to the end user. The fallacies of testing hold true, not everything can be tested and not all bugs will be found (that is, if you want to get to market), so we put the right bugs live. Following point 3 from Deming’s 14 Points: by doing more upfront (in the form of acceptance) and focussing on and building in quality, we eliminate the need for “mass inspection”.
Error logging and Customer Experience tracking tools, like TeaLeaf, provide instant feedback on any issues that do happen to creep into production.
Continuous Integration and Continuous Test Runs
An agile testing must-have, we use TeamCity to continuously run our unit tests on each check-in. We also execute our Cucumber acceptance tests on scheduled runs. The status of the builds are visible on dedicated monitors around the office as well as a nice 6′ projected screen.
Altogether
The most radical part of our process is probably the lack of traditional testers. We do not, however, lack testing. We focus on and assure quality in what we develop as we develop it. As a result we have seen the quality of output improve, the rate of throughput increase and our developers thrive as we constantly deliver correct, tested software.