TrainingConferencesAbout UsContact UsAdvertiseSQE.comRSS Feed

StickyMinds.com: brain food for building better software

Log In
 Clarify Your Search Criteria

Tips on Using Our Search Feature(s)
 
StickyMinds.com Home
ResourcesTopicsCommunityPowerPassBlogs
Home  >  Detail: Secrets to Automated Acceptance Tests



A StickyMinds.com Original
Article Picture
Secrets to Automated Acceptance Tests

By Jeff Patton

Send This Content to a FriendGet a Short Link to This ContentPrint This ContentSee User Comments About This Content

Summary: Has your team been on the search for a fully automated acceptance test? Before you set out on that adventure, check out some of the accomplishments and perils behind the quest for complete automation, as explained by Jeff Patton in this week's column. Fully automated acceptance tests may seem like the solution to many problems, but you should know that it comes with a few problems of its own.


Avnet
In the years that I've been involved with agile development, I've noticed an ongoing crusade for a holy grail that teams have been striving to reach: fully automated acceptance tests. There are some technical reasons why this crusade is difficult, but more importantly there are good reasons why automating some types of tests too early can be a bad idea. 
 
Unit Tests Verify Code Modules 
Agile developers generally divide automated tests into two types: unit tests and acceptance tests.  
 
It's becoming more common for developers to write unit tests as they write code. They usually write unit tests to the internal interfaces of the code modules being created. Writing test first helps to specify the module being developed. Once they've written the code and basic unit tests have passed, developers commonly beef up those test cases with boundary conditions, incorrect input, and error handling. 
 
This practice generally works pretty well. When all developers write tests, most every line of code becomes supported by a body of automated unit tests that is executed against the entire code base. Running those tests regularly with every code check-in confirms that the code behaves as expected when the tests were written.  
 
Unit Tests Help Avoid Bugs Getting into the Code Base 
When a developer adds or changes an existing code module, he sometimes sees unexpected failures in test that seem unrelated to the code he's working on. If you're a developer, then these are the times when you probably just can't help grinning. You’ve been investing heavily in this unit-testing practice, and, in one quick run of a testing framework, that investment pays a dividend by showing the failing test and with it the approximate location of the bug you've unintentionally injected. The failed test in the module you weren't working on pointed out a code dependency you weren't aware of--one you can address before you check in the new code you've just written. Thus, you avoid injecting a bug that may or may not have been found later through other forms of testing. 
 
Well-written unit tests cover a single module of code. Unit tests help with design changes or improvements to code by verifying that things still work correctly in all other parts of the code after the change is made. Unit tests are pretty easy to write. And, when making changes, the impact to the test code base is usually limited to the tests that verify the code you're changing. 
 
But unit tests have their limits. They work at a granular level--code module by code module. They're not easily readable by business people and aren't written at a high enough level to test full business-process flows.  
 
Acceptance Tests Often Verify System Use 
In an ideal agile-development world, the person specifying the software would write acceptance tests as executable requirements, and running those acceptance tests once the software is built would confirm that the requirements were met. Automating all acceptance tests has been a goal for many teams for years now. Some have even succeeded. 
 
But things start to get a bit sticky when tests are written to control the software from the user interface. These sorts of tests may start up the application, log in as a test user, and drive through a series of screens, entering information and pushing buttons just as a user would. They're amazing things to watch, and having a body of these tests exercising your system does give you confidence that the system does indeed work. 
 
Acceptance Tests are More Expensive 
These acceptance tests can be more time consuming and difficult to write. Because they simulate use, they often duplicate a lot of routing user activities, like logging in or opening a file. They often execute lengthy scripts that take the same actions a user would take at the keyboard and mouse. 
 
Automated acceptance tests are often written by different people with different skills, such as technical testers. They often write the tests at a different time than the code is written--often long later, after the code is done. 
 
Running these tests isn't quick either. In many organizations these tests take hours to run, so they're often only run at night or at fixed times during the day. And they're often run on code after it's checked into the code base, so they often don't prevent bugs from getting into the code, just point out that they're there. 
 
Failed Acceptance Tests Often Deliver News Too Late and to the Wrong Person 
For all these reasons, we don't get that happy feeling the developer gets when he sees a unit test fail. When an acceptance test fails, it's usually a long time after the offending code has been checked in. In fact, a lot of code may have been checked in. This makes finding the offending code difficult. Also, it's not always clear who should be finding and fixing the issue. It's not the person who wrote the test, if his is a role that writes tests and not code. It's not clear which developer should fix the code, and, even if it was, that developer probably already has moved on to doing something else, so now it's an interruption. 
 
I see many organizations struggling to keep their acceptance-test code bases working. It's common to have many tests failing every day. When some tests are fixed during the day, more things are broken the next day. I've seem many teams just give up. 
 
Acceptance Tests Can't Confirm That We'd Accept the Software 
There’s a simple reason why acceptance tests break more often than unit tests. Just like unit tests, they only verify what we understood when we wrote the tests. And herein lies the problem. 
 
In my last column ("An Uncomfortable Truth about Agile Testing"), I invoked the old definitions of verification and validation, where verification confirms the product was built as specified and validation confirms the product is fit for use or delivers a desired benefit to its user. This last bit, validation, is often subjective. The decision of whether it's delivering benefit isn't something that can be asserted in an automated test; you need to see it and use it.  
 
But that's not all. 
 
For much of software--especially commercial software--it needs to be easily learnable, efficient to use, and aesthetically pleasing for it to deliver its desired benefit. Even if it's not commercial software--for example, something like your company's handmade, internal, time-tracking system--you'd still like it to have these qualities. But again, these are qualities that can't be tested by automated tests. 
 
The corner I continue to see teams paint themselves into is one in which the team tries to automate acceptance tests before the software has been validated.  
 
Acceptance Tests Written Early Break When You Do the Right Thing 
A common pattern I see is acceptance tests--particularly those running the application through the user interface--being written along with the code. They verify that the code was written as specified. Everything's checked in, and then some time later the system is shown to end users or business stakeholders. As you’d expect, they see opportunity for change and for improvement. The change may be to move a couple fields around the screen, to relocate links or buttons from one screen to another, or to completely change the workflow in hopes that the application will be more efficient. There may be no underlying business-rule or system-behavior changes. But, these are the sorts of software changes that cause a cascading break in potentially dozens of acceptance tests.  
 
You did the right thing by showing the software to your stakeholders, and your reward is both code to change and lots of tests to fix. No good deed goes unpunished. 
 
Validate Frequently, Automate Verification After 
It's the areas of our system that are subjectively evaluated that are most prone to change. Validating the user interface in particular is a subjective endeavor. Automating tests that verify this subjective stuff before the software is validated is risky. Because of their higher cost of construction, higher cost of change, and slower rate of feedback, I'd suggest automating acceptance tests after the software is validated and considered reasonably stable.  
 
Please don't interpret this as a suggestion to defer automation until late in development. On the contrary, it's a suggestion to increase the rate of user and stakeholder involvement and validation. The sooner we validate, the sooner we can automate, and the sooner we can call our software "done."


About the Author
Jeff Patton leads teams of Agile developers to build the best software possible. He proudly works at ThoughtWorks. Jeff's series of columns on software design and pre-design tips appears regularly on StickyMinds.com. Jeff's blog, presentations, and other articles can be found at www.agileproductdesign.com. Among Jeff's accomplishments, he can add winning the 2007 Gordon Pask Award, which he received at the Agile2007 Conference in August.

Back to Top
 

StickyMinds.com Weekly Column From 6/16/09 

Member Comments
Add Your CommentCollapse Comments
 
Comment:    
by David Peterson 6/19/2008

The secret to writing acceptance tests is to write them in terms of goals, not solutions. If you write acceptance tests in terms of the UI then they will break when the UI changes. If, instead, you describe behaviour in terms of business domain concepts, this doesn't happen. In fact, the tests can outlast the application. Google for "Concordion" to see a different approach.

Author's Response:
6/20/2008    
Great advice David. Creating really durable automated tests is a real art form.

 
 
Comment:    
by J. B. Rainsberger 6/18/2008

I like this article, Jeff, but I'd like to point out that programmers can automate more tests in advance without risking a ripple effect when a customer wants to move a field around.

We know that many designs exhibit high coupling between "the UI" and "the logic", and teasing that coupling apart--mostly moving (business) logic out of the UI--is one step towards more flexibility, less ripple effect and more valuable automated end-to-end tests. We have all seen it. I invite programmers to take one more step.

Inside "the UI" I find two major kinds of code: UI toolkit client code and more general toolkit-neutral code. When I format a monetary amount as "$12.50", I can make that decision without involving the UI toolkit; but when I decide to display the text "$12.50" as a label or in a text field, I need to involve the UI toolkit in that decision. I invite programmers to separate their UI into presentation logic (UI toolkit neutral) and rendering logic (UI toolkit specific). If you do this, you will have an "abstract UI" or "presentation layer" you can test without drawing a real UI. These tests run quickly because they run in memory without having to paint a screen or invoke a UI toolkit component of any kind. You don't need end-to-end tests here. When someone decides to move a field around, none of your presentation layer tests need to change, and you avoid the ripple effect. Yes, your end-to-end tests change, but over time you'll automate fewer of those, preferring instead to automate the presentation layer tests.

So programmers, do your worst! Introduce a true presentation layer into your design, starting with the next screen or page. You'll thank yourself, and maybe me....Collapse Comments

Author's Response:
6/20/2008    
Thanks for this response JB. As always, you're dead right.

Haven't you made a case in the past for focusing more on unit level tests, and less on higher level acceptance tests?

 
 
Comment:    
by Srinivasan Desikan 6/17/2008

Good article and excellent points. However for a moment I want to play the role of a Devils advocate to capture other perspectives. Acceptance testing in general are classified into user acceptance testing (UAT)which is done by test engineers and customer acceptance testing (CAT)which is done by Customers. Both UAT & CAT are not run as many times as unit or regression tests and ROI of automation is LOW, since frequency of execution is too low. Where as complexity of such acceptance test automation is quite high as this particular test deals with entire system/product and hence it doesn't lend itself as a strong candidate for auomation. However in the world of Agile, acceptance testing has totally different meaning. Agile methodologies uses "test driven coding method" where coding is done based on acceptance tests and are fully automated. Since the code is validated based on acceptance tests, you should map it next to "unit test" in all your calcuations as these accptance tests are run daily and with 100% pass rate. These accptance tests in agile world are run almost daily to make decision "integrate or toss" and hence frequency of these tests are quite high and a good candidate for automation. This paradigm change in thinking is needed and we can't map each type of testing the same way in traditional testing and in Agile methodologies.

It is a wondeful article, thanks and my perspectives here doesn't take any credit away from this well written article....Collapse Comments

Author's Response:
6/20/2008    
I love the term "integrate or toss." I like automated tests that stop us from integrating bugs or problems into our code base. Unfortunately I see in practice, and I suspect you do to, agile teams with acceptance test suites that run after integrating resulting in an "integrate then debug" strategy.

 
 
Comment:    
by Harry Thens 6/16/2008

Jeff, as a tester and test automation specialist, I have seen many of the issues you mention here first hand. You make several excellent points in this article and I really enjoyed reading this. However, I see automated testing as three parts, namely unit, regression and performance. These are the testing tasks most often automated. Acceptance testing, by definition, is very subjective and therefore does not lend itself well to automation, as you point out here. I would refer to automated functional testing as Regression testing, rather than Acceptance testing. Perhaps this distinction would clear up some of the confusion.

Author's Response:
6/20/2008    
Harry, good points. I think I completely neglected performance tests in the article, and referring to tests as "regression tests" is a good ideal For me it helps point out a concern of mine - that it's risky to regression test functionality we've never validated.

 
 
Comment:    
by Bob Edwards 6/16/2008

Software development (whether production code or test code) is a highly iterative engineering endeavor, like most other engineering endeavors, and this dynamic nature at least allows, if not encourages, change - especially in our modern world of agile development, scrum, etc... Unlike building a bridge or a sewer, however, software quality (Fitness for use by the customer) is also a moving target, as was outlined in your example. In my experience, as relates to your article, one of the differences between good and great testers is recognizing *when* the right time is to craft a particular piece of automation.

Unit tests are a "first chance" test, focused on a very small piece of the code. Given the granularity, its likely that unit testing will find most issues that pertain exclusively to that piece of code, but very unlikely that any interoperability issue or functionality failure would occur.

Acceptance testing at the same level is the first validation opportunity, and mostly helps confirm that the piece of code, as written, satisfies the requirements of the customer as defined by the team (fitness for use).

As more modules become available, the second level of testing comes into being - interoperability. If I have library A and library B, do they work together as expected.

Towards the end is when most teams start crafting the GUI (if the product has one). GUI automation, in my experience, is amongst the most expensive automation both because of the complexity of tools needed to make such automation (Visual Test, anybody?), but also because the GUI is the element of the product most likely to change. Frankly, this also means that in some cases, full automation is a wasteful endeavor. Once you've invested the time and money in crafting such automation (if you do, indeed, get it done before the marketing team are screaming their heads off about whether they can ship yet or not), the amount of time you get to continue to use it can make such automation a poor investment. In many case you may be better served to keep some manual testers poking away at the product, because unlike an automated test, a manual tester can change when the product changes and still interpret how to represent the customer (fitness for use again).

Its not just what to write (and what not to write) with regards to automation, its knowing which pieces to write first.

Happy testing!

...Collapse Comments

 
Back to Top



 
Ads By Google
What's This?
 
 



Home   |   Resources   |   Topics   |   Community   |   PowerPass



© 2010 StickyMinds.com. All rights reserved.
StickyMinds.com is a division of Software Quality Engineering.
Privacy Policy    Terms & Conditions    Link to StickyMinds.com    Feedback


Infosys

TechExcel, Inc.




STAREAST 


Better Software Conference