Tuesday, January 25, 2011

Evolution of Automated Testing

In the Agile world, and increasingly, in software development in general, automated testing is a key ingredient in delivering quality software. It's one of the many reasons why Agile has become so successful and is a component to any long-term, sustainable effort. Automated testing blurs the lines between the QA and the Dev. Both parties need to work together to produce a solid piece of software.

If your code has been developed in a "non-Agile" way, meaning code that is not easily testable, we need to work on paying back that technical debt. (Technical debt is anything in your code that wasn’t done cleanly. You know it’s there, and eventually you’ll have to pay it back. Unfortunately the interest rates are usually obscene!) There are many ideas on ways to do this, including Defect Driven Testing (find a bug, write a test).

Today I don’t want to discuss writing testable code for new features, but rather how to deal with our current technical debt. How do we move our code (and developers!) from a manual testing process to a more automated testing mindset?

 

clip_image003 clip_image001 clip_image005

How do we get there? Iteratively, of course!

Always use an iterative, phased in approach when introducing automated testing to your development team. Remember, the goal isn’t to fix everything overnight and make sure everything is being done The Right Way. That approach often creates so much churn that the team gives up and reverts to old habits. Our goal is create lasting, sustainable change.

First, let's define different umbrellas of automated testing:

  • Manual - tests which cannot be automated, it requires human interaction and a human eye.
  • GUI - tests that will mimic the user clicking buttons in the UI to perform end to end testing
  • Functional - tests that can provide end to end functionality testing that occurs right below the user interface level.
  • Integration – tests requiring an external source such as a database.
  • Unit - tests that are all on the front end, no external sources required but which test a small amount of code.

     

    Phase 1

    clip_image007

    With legacy code, we all start with manual testing. A QC person manually tests the same test case over and over again throughout the entire system through different releases. The goal is to move off of the manual boat and onto a more automated boat!

     

    Phase 2

    clip_image009

    While most of our tests are still manual, an introduction to automated GUI testing has begun. Typically, in legacy code, the business logic and the user interface is tightly coupled. Because of this, GUI tests are the only automated way to provide a full, end to end test of the system. GUI tests mimic the end users actions on the screen. It's as if a person is there performing actions on the screen. While GUI tests are slow, brittle, and prone to error, this is not the ideal way to automate tests but is the biggest bang for the buck to start off with that typically requires very little, if any, code refactoring.

     

    Phase 3

    clip_image011

    Introduce a new form of testing, the integration test. This layer of testing is not designed to be end to end as a GUI test does, it does test smaller chunks of code but are more reliable than a GUI test and can be ran much more frequently. Starting out, integration tests can be hooked up to a Continuous Integration (CI) server to alert the developers if they have broken a build and get it fixed sooner rather than later.

    This is the first major paradigm shift that developers need to learn is to how to write code that can be easily testable. This type of testing will more than likely require code refactoring in order to create independent tests.

    In this phase developers need to start thinking about how to loosely couple their code in order to further test it. Ultimately we want to move into a very dumb User Interface.

     

    Phase 4

    clip_image013

    Unit testing is the fastest, most reliable type of test but tests the smallest amount of code. With unit testing, we create mock objects, run the data through a method or a small group of methods, and test the result. These tests are fast because they do not require connections to external sources like a database or a remote service.

    More code refactoring will be required in this phase. This phase will further introduce concepts such as Dependency Injection and IOC (Inversion of Control) in order to "fake out" data in order to isolate the specific method(s) we are testing for.

    In the end, because unit tests test the smallest chunk of code and are the most reliable type of test, we will have more of these kinds of tests than any other.

     

    Phase 5

    clip_image015

    Phase 5 is a refactoring/building stage. Armed with the knowledge of unit and integration testing and experience in refactoring code to write these tests, we need to build up our test suite. This phase will focus on paying back the technical debt that has accumulated over time and begin structuring our code in a testable manner.

    This phase will begin to introduce design patterns such as Model-View-Present (MVP) for Windows Development or even Model-View-Controller (MVC) for web development. Begin introducing how to develop and refactor code in this design patterns. Writing/refactoring code in a design pattern enforces a separation of concerns between the user interface and the business logic. This will allow us to test end to end, functional requirements, effectively testing as much code as possible without doing a GUI test.

     

    Phase 6

    clip_image016

    Now that we have refactored code in a much more testable manner, we need to introduce Functional Testing. The idea behind functional testing is that we test functional requirements from a business perspective. Having our code in the MVP design pattern will allow us to test functionality below the user interface. This will allow for faster, more reliable tests than GUI tests and it keeps our tests running even when the GUI is changed.

    The end goal is solid software. How does test automation get us there? It takes time, and there is some risk getting there, but if we take short, iterative steps, it can be done! Be sure that when developers are writing tests that a member of QA pairs with them (or at least reviews each test). They’ll ensure the developers write valuable tests. Over time you’ll find the developers learn what the QA team members need tested, and the QA team will start to learn what types of scenarios are easiest to automate. This will result in even faster and more effective test creation in the future!

     

    Tips

    1. At minimum, create different projects for different types of tests. Create an integration test project, unit test project, and a GUI test project. If you have a large number of GUI tests, you may want to consider having that as a separate solution and have those broken down. One advantage of breaking tests up into multiple projects; you decide which tests can run when on a Continuous Integration server.

    2. Run unit and integration tests as part of the build on the CI server. This will guarantee developers are notified in a timely manner if they have broken code. The sooner broken code (and the test) is found, the sooner it can be fixed, and the cheaper it is to fix!

  • Wednesday, January 12, 2011

    5 Characteristics for an Effective Daily Stand Up

    One practice of Scrum is a daily stand up meeting.  Why?  It serves as a status update of how the team is doing and allows each team member to feel an ownership and be accountable of the process. 

    Characteristics of an Effective Stand Up

    1. Stand Up! - this keeps the meeting short and more engaging.  Harder to fall asleep when you're standing up!
    2. Consistent - same bat time, same bat channel, and be the top priority of every team member to attend.  Ideally, they occur in the mornings, right after everyone has arrived, to set the direction of the day.  If your team has a staggered work schedule, make it late enough in the day so people don't use the stand up to start their day.
    3. Quick - each person has a maximum of 60 seconds to answer the three golden questions:
      1. What did you do yesterday?
      2. What are you doing today?
      3. What roadblocks are you facing?
    4. Focused - the person facilitating the meeting (typically the Scrum Master), needs to keep team members focused and engaged on those three questions.
    5. "Meeting after the Meeting" - team members often need clarification from another team member(s), talk to them after the stand up, not during it, so as to not take up everyone else's time.

    Tips

    • Use Skype for Remote team members - use Skype or some other voice communication tool.  I'm on a team with one remote person but the other team members are in the office.  The team stands up around a PC with a web cam, a desktop microphone, and desktop speakers, and Skype the remote member.
    • Make sure team members answer questions effectively.  "I did stuff yesterday and am doing more stuff today", doesn't count!  We have a ticketing system for each story.  The answers should give an adequate status of what the team member is working on.  For example, "I'm working on the Create functionality for creating a member and should be done with it tomorrow.  I have no blocks" is much more effective. 
    • Follow up the next day if something was expected to get done but did not and determine why not.
    • Foster an environment of supportive accountability.  Keep your team members accountable to what they say they are going to do but encourage team members to help each other when needed!


    Additional Resources
    Martin Fowler’s - It’s Not Just a Stand Up
    Daily Scrum