Thursday, 8 December 2011

Some Definitions - Testing Techniques 9

I think that I’m coming to the end of my series of blogs on testing techniques, and it feels like it’s been along haul. One of the things that has become clearer to me is that approaches to testing are still in their infancy and as such are a definite source of contention or discussion amongst developers - and that’s a good thing. I suspect that we are at a point in the history of our profession where the discipline of writing tests is only just gaining ground and will one day be common place and taught as part of elementary programming classes1. Today’s blog provides a summary of the of the terms used in my previous blogs in this series.

Unit Tests

I covered the definition of a unit test in part two of this series of blogs, giving the views of Shane Warden, who in his book The Art of Agile Development states that unit tests should run at a rate of “hundreds per second”; Michael Feathers, who in his book Working Effectively with Legacy Code states that a unit test is not a unit test if:

  1. It talks to a database.
  2. It communicates across a network.
  3. It touches the file system.
  4. You have to do special things to your environment (such as editing configuration files) to run it.

I also quoted Roy Osherove, who in his book The Art Of Unit Testing sums up a good unit test as: "an automated piece of code that invokes the method or class being tested and then checks some assumptions about the logical behaviour of that method or class. A unit test is almost always written using a unit testing framework. It can be written easily and runs quickly. It's fully automated, trustworthy, readable and maintainable".

Unit tests can be summed up using the FIRST acronym: Fast, Independent, Repeatable, Self Validating and Timely.

When to Use Unit Tests

Unit tests are the bread and butter of testing. If you employ Test Driven Development, TDD, then you write failing tests before you write your production code. If you don’t use TDD, then at least write your tests at the same time as your production code i.e. write a method and then write its tests. This technique doesn’t involve the paradigm shift that accompanies TDD, but it’s much better than writing tests after you’ve written all the code, which is usually considered tedious by developers. There should be one test for every scenario, which translated into plain English means every path through your code: both sides of every if statement and every case of a switch statement. In short, every project should have hundreds of Unit Tests and you should have the confidence that if you change a part of the code then you won’t break something.

Stubs

Stubs are used to isolate an object under test from the rest of the system. They are objects that are injected into your object to replace real objects in test situations. Martin Fowler defines stubs, in his essay Mocks Aren’t Stubs as:

“Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'”

...whilst a similar definition, taken from The Art of Unit Testing is:

“A stub is a controllable replacement for an existing dependency (or collaborator) in the system. By using stub, you can test your code without using the dependency directly.”

Mocks

Mocks are replacement objects used to imitate, or mock, the behaviour or roles of production objects. This really means checking that an object under test calls methods on a mock object as expected with the test failing if it doesn’t; hence, you’re asserting on the correctness of method calls and the execution path through your code, rather than, in the case of a regular unit test, the return value of the method under test.

Integration Tests

Integration tests are the opposite of unit tests. The idea behind integration tests is to prove that your objects collaborate with each other and the system around them. To paraphrase Michael Feathers, integration tests CAN:
  1. talk to a database.
  2. communicate across a network.
  3. touch the file system.
  4. require you to do special things to your environment (such as editing configuration files) to run it.
Roy Osherove in the Art of Unit Testing states that an “integration test means testing two or more or more dependent software modules together as a group”. For me this constrains the definition a little too much after all, in testing objects in a single module you can access a database or file system whilst figuring out if your objects can collaborate.

In projects I’ve previously worked on, there’s usually been a module specifically written to hold integration tests. This is because integration tests are less numerous than unit tests (perhaps at a ratio of 1:10) and, by virtue of the fact that they access their environment, are usually substantially slower and therefore corralling all integration tests into their own Maven module means that they don’t have to run every time you build a module, speeding up build and development time.

End to End Integration Tests

I’ve covered End to End tests in detail in the second blog in this series, so to summarise, they can be defined as a special case of integration tests in that the test commences at, or just behind, a system boundary and executes through all layers of the system. Where the system boundary, or just behind the system boundary is a matter for debate. In terms of a Spring MVC app, there’s no reason why an end to end test shouldn’t start at your controller code ignoring the browser and dispatcher servlet. After all, I suspect that the Guys at Spring have tested their code thoroughly, so why should you waste time testing it? Also, testing what the front end looks like s a whole different kettle of fish.



A list of Blogs on Testing Techniques


1I often suspect that testing techniques are not actually taught in collages and universities - but I’ve no evidence of this. If there are any academics out there who can tell me that unit testing is taught, encouraged and an integral part of their Computer Science Degree courses then I’d be happy to hear from them.

No comments: