Sunday, December 20, 2009

Unit Testing 101 Guidelines Part 1

See also Unit Testing Guidelines Terminology, Part1, Part2, Part3, Part4

What is Unit Testing?

A unit test is a focused automated test for one member in a class.  This means it’s a small piece of .Net code designed to test one member of a class.  Given control of the input to a method the output can be predicted (with knowledge of the code or business function) and then compared to a predetermined constant. If it does not meet this expectation outcome the test fails.  

For example if you have a method Add(x, y) that takes two integers you know (based on the specification) that passing in 2 and 3 should return 5.

Unit tests are built over time and stored in large libraries of tests. These libraries are then used to test a lot of code very quickly and covering a good deal of code.  This fast high code coverage testing can then be used to gauge the success of new code (has a newly added feature somehow broken existing code aka ripple-effect).

The style of inputs generally fall into two categories: common use case input, and fringe input intended to see if the method gracefully handles unexpected data.

Unit tests are intended to be isolated and independent from one another. This means that one test running should not interfere with others also running at the same time or subsequently.  For the sake of speed, applications that run unit tests quite often run tests in parallel on multiple threads; doing so should not fail the tests. Making use of static state variables will cause tests running in parallel to interfere with each other.

Unit testing is strictly targeting development and developers.  However unit tests should always be automated into the master build process.  This gives an indication of build quality and ensures QA testers do not start testing a broken build.  A broken build is further described as a build that does not compile or a build in which not all tests are passing.

Unit testing is only possible on code that has been designed to be tested.  Designing for testing essentially means that class design allows for ways to provide alternatives (stubs and mocks) for all dependencies of the class.

When testing a method within a class you go through a process of “mocking out” dependencies so the class under test does not try and call other production code outside the class. For example to ensure a class does not call a live service or database. This creates an isolated test environment that focuses the testing to the one class and method. Only code in the class under test can fail the test.

What is Test Driven Development (TDD)? 

Test Driven Development is sometimes used in conjunction with Unit Testing. Unit testing can be fully utilised without following a Test Driven Development process. However by following TDD high code coverage is achieved more rapidly and code tends to be more concise and less complex.

WIKIPEDIA: It’s an approach focused on writing only the code necessary to pass tests, resulting in cleaner and clearer designs than is achieved by other methods. It cuts out extra functionality that is outside of the current scope. This definitely results in simpler, easier to implement and follow code, but means that extensibility becomes a problem for future projects unless extensibility is part of the original specification and scope.

The main principles are:

  • —The main principal is to KISS YAGNI. 
  • Keep It Simple Stupid, You Ain’t Gunna Need It. 
  • Developers are given Use Cases with the software specifications. 
  • Write failing tests first that match Use Cases. 
  • Write code only to make tests pass. Results in a clean uncomplicated easy to use application.

No comments:

Post a Comment