Tuesday, 27 April 2010

A recent email I sent to a friend who has started automated testing


Here is a quick email I threw together for a friend who has started writing automated tests and asked if there is a reason to have lots of different kinds of tests covering the same area. Yes, it's simplistic and I'm sure a bunch of ThoughtWorkers would kick me and say it is better explained in other ways but I think this is a good summary. In case it helps others, here it is...



OK, this is the way I structure testing of an application. This works when the tests are written retrospectively or if the application is written in a test driven manner.

There are three types of tests:
  1. Functional tests - UI testing that uses the terms of the users/business. You'll see tools like Selenium with junit/nunit/rspec used at this level. Functional areas of the application are tested in a similar workflow to what I user would use. Happy path comes in here for primary workflows. Deliberate error (validation and business logic) and exception testing at the highest level occur now;
  2. Integration tests - these tests are used when you are plugging all the bits of your system together. Bits can mean layers, components within a layer, or dependencies outside of your system (third party web services, etc...). The point of this is a test interfaces and APIs that are public to the component or application parts. You test input and output in a black box way. Again, with all good data and then causing errors and exceptions;
  3. Unit tests - These tests are the very specific low level tests that check that a unit of functionality is working. This can be at a class level, library or component. You'll see mocking frameworks used here to imitate data sources or connecting systems. At this point, you do not want to be distracted by the possibility of functionality external to this unit causing issues so it doesn't talk to anything and gets all input or directs all output to mocked objects.
The reason for the three layers individually is explained above in each point. The reason you do them together is that with continuous integration and thorough test suites, you can easily track down where an error is occurring and focus in on the area of concern. All these tests should be used together.

This is a starting point and written at a high-level. Ask me if you need it clarified further.

1 comment:

David Keaveny said...

How far do you go with your mocking? I've found that abstracting the system clock is very useful - the amount of code I've written before that calls DateTime.Now and then does some sort of check that is impossible to verify under unit test conditions is incredible. I hate unit tests that pass on a Monday and fail on a Friday.