Unit Testing

Unit Testing

UNIT TESTING, also known as COMPONENT TESTING,  is a level of software testing where individual units/components of a software are tested. The purpose is to validate that each unit of the software performs as designed.

Definition by ISTQB

  • unit testing: See component testing.
  • component testing: The testing of individual software components.

Elaboration

A unit is the smallest testable part of any software. It usually has one or a few inputs and usually a single output. In procedural programming, a unit may be an individual program, function, procedure, etc. In object-oriented programming, the smallest unit is a method, which may belong to a base/super class, abstract class or derived/child class. (Some treat a module of an application as a unit. This is to be discouraged as there will be many individual ‘units’ within that module.) Unit testing frameworks, drivers, stubs, and mock/fake objects are used to assist in unit testing.

Defects are usually fixed as soon as found and they are not formally reported and tracked.

Analogy

During the process of manufacturing a ballpoint pen, the cap, the body, the tail, the ink cartridge and the ballpoint are produced separately and unit tested separately.

Method

Unit Testing is usually performed by using the White Box Testing method and is normally automated.

Tasks

When is it performed?

Unit Testing is the first level of software testing and is performed prior to Integration Testing. Though unit testing is normally performed after coding, sometimes, specially in test-driven development (TDD), automated unit tests are written prior to coding.

Who performs it?

It is normally performed by software developers themselves or their peers. In rare cases, it may also be performed by independent software testers but they will need to have access to the code and have a proper understanding of the architecture and design.

Benefits

  • Unit testing increases confidence in changing/maintaining code. If good unit tests are written and if they are run every time any code is changed, you will be able to promptly catch any defects introduced due to the change. Also, when you make codes less interdependent to enable unit testing, you also lessen the unintended impact of any code change.
  • Codes are more reusable. In order to make unit testing possible, codes need to be modular. This means that codes are easier to reuse.
  • Development is faster. How? If you do not have unit testing in place, you write your code and perform that fuzzy ‘developer test’ (You set some breakpoints, fire up the GUI, provide a few inputs that hopefully hit your code and hope that you are all set.) But, if you have unit testing in place, you write the test, write the code and run the test. Writing tests takes time but the time is compensated by the less amount of time it takes to run the tests; You need not fire up the GUI and provide all those inputs. And, of course, unit tests are more reliable than ‘developer tests’. Development is faster in the long run too. How? The effort required to find and fix defects found during unit testing is very less in comparison to the effort required to fix defects found during system testing or acceptance testing.
  • The cost of fixing a defect detected during unit testing is lesser in comparison to that of defects detected at higher levels. Compare the cost (time, effort, destruction, humiliation) of a defect detected during acceptance testing or when the software is in production.
  • Debugging is easy. When a unit test fails, you need to debug only the latest changes. With defects detected at higher levels of testing, you need to assess changes made over the span of several days/weeks/months.
  • Codes are more reliable. Why? I think there is no need to explain this to a sane person.

Tips

  • Create a proper unit test plan. [If not documented, at least in your head.]
  • Find a test automation tool/framework for your programming language.
  • Create test cases focusing on areas that impact the behavior of the system the most.
  • Isolate the development environment from the test environment.
  • Use test data that is the same as or similar to that of production.
  • Before fixing a defect, write or modify a test that exposes the defect. Why? First, you will later be able to catch the defect if you do not fix it properly. Second, your test suite is now more comprehensive. Third, you will most probably be too lazy to write the test after you have already fixed the defect.
  • Write test cases that are independent of each other. For example, if a class depends on a database, do not write a case that interacts with the database to test the class. Instead, create an abstract interface around that database connection and implement that interface with a mock object.
  • Aim at covering all paths through the unit. Pay particular attention to loop conditions.
  • Make sure you are using a version control system to keep track of your test scripts.
  • In addition to writing cases to verify the behavior, write cases to ensure the performance of the code.
  • Perform unit tests continuously and frequently.

One more reason

Lets say you have a program comprising of two units and the only test you perform is system testing. [You skip unit and integration testing.] During testing, you find a bug. Now, how will you determine the cause of the problem?

  • Is the bug due to an error in unit 1?
  • Is the bug due to an error in unit 2?
  • Is the bug due to errors in both units?
  • Is the bug due to an error in the interface between the units?
  • Is the bug due to an error in the test case?
  • Is the bug due to an error in the test execution?
  • Is the bug due to an error in the test environment?

Unit testing is often neglected but it is, in fact, the most important level of testing.

Last Updated on March 12, 2023 by STF