Unit_Testing

Unit Testing: Everything You Need To Know

What is Unit Testing?

Unit testing is a software development process in which the smallest testable parts of an application, called units, are individually and independently scrutinized for proper operation.

The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as expected.

Each unit is tested separately before integrating into modules to test the interfaces between modules. Using effective Unit testing, a large percentage of defects are identified. Unit testing is performed by developers.

Each module that is developed by designers needs to be tested individually to verify proper operation so that any faulty module can be fixed immediately rather than let it exist and then cause some major issues in the integration phase.

Once all of the units in a program are working efficiently and without any bugs, larger components of the program can be evaluated using integration testing. Though Unit testing may be time-consuming, tedious, and requires thoroughness on the part of the development team, in the long run, it can avoid major pitfalls in the software.

Acceptance Testing

Why Do We Need to Do Unit Tests?

We need to do unit tests because doing so helps developers know whether the unit is functioning or not. Any error or bug in the code can be identified easily and fixed as early as possible.

Software developers are responsible for performing unit tests as they have created each component. The next stage of testing, called integration testing is carried out by a team of testers. The testers are not well-informed about the internal structure of the software, so if unit tests are skipped, it will get more difficult to find errors, and deployment will take longer.

The Different Types of Unit Tests

Unit tests are of two types- automated and manual.

Automated Unit Testing

Automated unit testing is a process of checking scripts and identifying errors automatically. It is done with the help of a specialized automated testing tool. Developers today use this approach to test scripts because it saves time, reduces human error, and also improves software quality.

Advantages of Automated Unit Testing

  • Reduces cost in the long run since it doesn’t require a team.
  • It is faster than manual unit testing.
  • Test cases can be repeated to find previously undetected errors.
  • Test cases can be reused to save on maintenance costs.
  • It provides accurate results due to a lack of human interference.
  • Boosts developer’s productivity by automating tasks.
  • Improves scalability.
  • Allows batching of multiple test scripts.

 Disadvantages of Automated Unit Testing

  • Installation is more expensive than manual unit testing.
  • Requires a professional tester.
  • It doesn’t support random testing.
  • There is environment limitation.
  • Since automated testing doesn’t involve human observation, it can’t guarantee user-friendliness.
  • It is not suitable for dynamically changing GUI designs.

Manual Unit Testing

Manual unit testing is the process of checking scripts and identifying errors manually. Such tests are usually carried out by a QA analyst without using automation tools. Manual unit testing is ideal when there’s a small number of unit tests to be executed, when a quick fix is needed, or when automation gets expensive.

Manual unit testing comes in different types for different purposes and software. The most common types are-

  1. Black-Box Testing
  2. White-Box Testing
  3. Unit Testing
  4. Integration Testing
  5. System Testing
  6. Usability Testing
  7. User Acceptance Testing

Advantages of Manual Unit Testing

  • It doesn’t require coding knowledge.
  • Since it involves human observation, testers can find usability and user-interface issues.
  • No environment limitations.
  • It is suitable for dynamically changing GUI designs.

Disadvantages of Manual Unit Testing

  • It requires plenty of human resources.
  • The process is slow.
  • Test cases are not reusable, so whenever there’s a minor change, the test cases need to be written from the beginning.
  • There can be more errors since manual testing is done by humans.
  • Not suitable for load and performance testing
  • Can’t be used to compare two databases.
  • Repeating tests can be tedious and time-consuming.

Unit Testing Techniques

Unit testing techniques utilize three methods- structural, functional, and error-based techniques.

Structural Techniques: It is a White box testing technique that uses an internal perspective of the system to design test cases based on internal structure. It requires programming skills to identify all paths through the software. The tester chooses test case inputs to exercise paths through the code and determines the appropriate outputs. Major Structural techniques are:

  • Statement Testing: A test strategy in which each statement of a program is executed at least once.
  • Branch Testing: Testing in which all branches in the program source code are tested at least once.
  • Path Testing: Testing in which all paths in the program source code are tested at least once.
  • Condition Testing: Condition testing allows the programmer to determine the path through a program by selectively executing code based on the comparison of a value
  • Expression Testing: Testing in which the application is tested for different values of Regular Expression. 

Functional testing techniques: These are Black box testing techniques that test the functionality of the application. Some functionality testing techniques are:

  • Input domain testing: This testing technique concentrates on the size and type of every input object in terms of boundary value analysis and Equivalence class.
  • Boundary Value: Boundary value analysis is a software testing design technique in which tests are designed to include representatives of boundary values.
  • Syntax checking: This is a technique that is used to check the Syntax of the application.
  • Equivalence Partitioning: This is a software testing technique that divides the input data of a software unit into partitions of data from which test cases can be derived. 

Error-based Techniques: The best person to know the defects in his code is the person who has designed it.

A few of the Error based techniques are:

  • Fault seeding techniques can be used so that known defects can be put into the code and tested until they are all found.
  • Mutation Testing: This is done by mutating certain statements in your source code and checking if your test code can find the errors. Mutation testing is very expensive to run, especially on very large applications
  • Historical Test data: This technique calculates the priority of each test case using historical information from the previous executions of the test case.

Unit Testing Tools

There are various unit testing tools available on the web. Here are the most popular unit testing tools:

  1. JUnit: JUnit is a free unit testing framework for Java programming. It works by testing the data first before it is added to the code.
  2. NUnit: NUnit is a free unit testing framework for .NET languages. It allows the manual writing of scripts and supports data-driven and parallel tests.
  3. DBUnit: DBUnit is a JUnit extension that is also compatible with ANT. It is created for database-driven projects where it puts the database into a known state to avoid issues between testing periods.
  4. PHPUnit: PHPUnit is a unit testing tool for PHP language. It uses assertions to assert that a unit of the software behaves in a certain manner. Also, developers can use this tool to find out hidden errors in newly-produced codes.
  5. JMockit: JMockit is an open-source Java framework that integrates with JUnit and TestNG. It consists of APIs for mocking, faking, integration testing, and a code coverage tool.
  6. SimpleTest: SimpleTest is similar to PHPUnit in the way that is made for PHP language. It has support for SSL, forms, authentication, and proxies.
  7. Embunit: Embunit or embedded unit is a unit testing framework for programmers developing software in C or C++ languages. It allows developers to write test cases and define their behavior.
  8. EMMA: EMMA is an open-source toolkit used for measuring and reporting Java code coverage. It is useful in large-scale software development environments while accelerating an individual developer’s test cycles.
  9. ABAP Unit: ABAP Unit is a member of the xUnit family that utilizes ABAP code. It helps developers in verifying outcomes and validating the results of paths throughout their code.

How to Execute Unit Testing

Choose a suitable Unit Testing framework: There are various Unit Testing frameworks available for different programming languages, such as JUnit for Java, NUnit for .NET, and pytest for Python. Select a suitable framework and learn its syntax and features.

Create a test suite: A test suite is a collection of test cases that verify the functionality of a specific unit or module in the code. Develop a test suite for the unit you want to test.

Write test cases: Develop test cases that cover all possible scenarios and edge cases for the unit. A test case typically consists of inputs, expected outputs, and assertions that compare the actual output with the expected output.

Run the test suite: Use the Unit Testing framework to run the test suite. The framework will execute all the test cases in the suite and report the results.

Analyze the results: Analyze the test results to identify any failures or errors. Check the error messages and stack traces to understand the cause of the failure.

Fix the issues: If any test case fails, debug the code to identify the root cause of the failure. Fix the code and re-run the test suite to verify that the issue has been resolved.

Repeat the process: Repeat the above steps for all the units and modules in the codebase. Ideally, Unit Testing should be performed continuously as part of the development process to catch issues early and ensure that the code is robust and reliable.

Unit testing can be performed manually or automated. Automation is preferred and developers generally use Unit Testing frameworks to develop automated test cases.

Under the automated approach, developers write a section of code in the application just to test the function and later comment out and remove the test code when the application is deployed.

Developers can also isolate the function to test it more rigorously, which involves copying and pasting the code to its own testing environment to reveal any unnecessary dependencies between the code being tested and other units or data spaces in the product.

The workflow of Unit Testing includes creating test cases, reviewing and reworking them, baselining, and executing the test cases.

By following these steps, you can ensure that your code is thoroughly tested and free of bugs before it is deployed to production.

Unit Test Example

Example of an Android unit test:

public class ExampleUnitTest {

    @Test

    public void testAddition() {

        Calculator calculator = new Calculator();

        int result = calculator.add(2, 3);

        assertEquals(5, result);

    }

    @Test

    public void testSubtraction() {

        Calculator calculator = new Calculator();

        int result = calculator.subtract(5, 2);

        assertEquals(3, result);

    }

}

In this example, we’re testing a simple Calculator class that has two methods: ‘add’ and ‘subtract’. The ‘testAddition’ method creates a new instance of the ‘Calculator’ class, calls the ‘add’ method with two parameters (2 and 3), and then checks that the result is equal to 5 using the ‘assertEquals’ method. Similarly, the ‘testSubtraction’ method tests the ‘subtract’ method with two parameters (5 and 2) and checks that the result is equal to 3.

These tests are written using the JUnit testing framework, which is commonly used for unit testing in Android development. They demonstrate the basic structure of a unit test, which involves creating an instance of the class being tested, calling its methods with various inputs, and verifying that the outputs are correct using assertion statements like ‘assertEquals’

Angular Unit Testing:

import { ComponentFixture, TestBed } from ‘@angular/core/testing’;

import { MyComponent } from ‘./my.component’;

describe(‘MyComponent’, () => {

  let component: MyComponent;

  let fixture: ComponentFixture<MyComponent>;

  beforeEach(async () => {

    await TestBed.configureTestingModule({

      declarations: [ MyComponent ]

    })

    .compileComponents();

  });

  beforeEach(() => {

    fixture = TestBed.createComponent(MyComponent);

    component = fixture.componentInstance;

    fixture.detectChanges();

  });

  it(‘should create the component’, () => {

    expect(component).toBeTruthy();

  });

  it(‘should display the correct title’, () => {

    component.title = ‘Test Title’;

    fixture.detectChanges();

    const titleElement = fixture.nativeElement.querySelector(‘h1’);

    expect(titleElement.textContent).toContain(‘Test Title’);

  });

});

In this example, we’re testing a simple Angular component called ‘MyComponent’. The ‘beforeEach’ block sets up the test environment by configuring a ‘TestBed’ instance with the ‘MyComponent’ declaration, and then compiling the component’s template.

The ‘beforeEach’ block also creates a fixture object and assigns it to ‘fixture’, which we can use to access the component’s properties and methods during the tests.

The first test, ‘should create the component’, simply checks that the MyComponent instance is truthy, indicating that it has been successfully created.

The second test, ‘should display the correct title’, sets the component’s ‘title’ property to ‘Test Title’, updates the view using ‘fixture.detectChanges()’, and then uses the ‘fixture.nativeElement’ object to query the DOM for the ‘h1’ element that displays the title.

The test then checks that the element’s ‘textContent’ property contains the expected value (‘Test Title’).

These tests demonstrate the basic structure of an Angular unit test, which involves creating a fixture object for the component, manipulating the component’s properties and methods, and verifying the state of the component and its view using assertions like ‘expect’.

Advantages of Unit Testing

  • Unit testing allows developers to check the functionality of a component.
  • It allows developers to find out issues and fix them at the early stage of the development process.
  • It helps to ensure that each unit functions as expected, which results in improved software quality.
  • It allows developers to test the components of a project without waiting for others to be completed.
  • The modules can be reused.
  • It ensures faster development as developers can validate changes to the code instantly.
  • It serves as a documentation of the code and its behavior, making it easy for new developers to understand.

Disadvantages of Unit Testing

  • Unit testing isn’t a reliable option for detecting all the bugs in the code.
  • Writing test cases is time-consuming.
  • Whenever there’s an alteration of functions, the unit test for those functions also changes. So, there’s a greater maintenance cost.
  • It isn’t suitable for testing GUI code due to the complexity of the code.
  • Unit testing is challenging for legacy code because developers often have no idea where to start from.

Misconceptions about Unit Testing

  • Integration Tests will Catch all the Bugs Anyway: This is one of the common misconceptions of designers. The complexity of the issue rises while it passes through various testing cycles and then when the bug is raised during the later stages, the resolution time will be high as the scope of the bug widens. It is better to weed off the crop before it poisons the whole farm.
  • Programmer’s Dilemma: Most designers believe Unit testing is not required as it is time-consuming. They feel they are too good programmers and their software doesn’t need Unit tests. But in the real world, everyone makes mistakes. Real software systems are much more complex. Software behavior varies in different environments and with different scenarios. Coding is not a one-pass process. Enhancements to the code can be made only when we know the existing module is functioning as expected.
  • It Consumes Too Much Time: Developers are often in a hurry to complete their code and integrate it. Unit Testing is most often considered a useless activity, as they feel anyways the code will be tested by QA. There is no point in having a system that works but not exactly as it is supposed to function and is to be full of bugs. Practically, such an approach to development will often result in software that will not even run. The net result is that a lot of time will be spent tracking down relatively simple bugs which are wholly contained within particular units. Individually, such bugs may be trivial, but collectively they result in an excessive period of integrating the software to produce a system that is unlikely to be reliable. This can also lead to failure to meet the required deadlines.

Unit Testing Best Practices

Keep on a straight path proper unit testing
  • Ensure each Unit Test case is independent of the other. As the software is prone to changes during the Unit Testing due to enhancements/changes to the requirements. Hence any given behavior should be specified in one and only one test. Otherwise, if you later change that behavior, you’ll have to change multiple tests.
  • Test only one code at a time. It is always recommended to test each of the modules independently and not while all are chained together. Otherwise, you will have lots of overlap between tests, and changes to one unit may affect all other modules and cause the software to fail.
  • Name your unit tests clearly and consistently. Ensure that your test cases are easily readable so that anyone picking up Unit test cases can execute them without any issues. Ensure the test case nomenclature is consistent throughout.
  • Before changing a module interface or implementation, make sure that the module has test cases and that it passes its tests before changing the implementation. This way you can know that your changes didn’t break anything.
  • Always ensure the bug identified during Unit Testing is fixed before moving it to the next phase.

How to Write a Simple Unit Test Case

A test case refers to a document where actions are planned to determine whether a function works as expected. A well-planned test case facilitates developers to understand what needs to be done.

Below are the steps to write a unit test case for a simple login function with valid data.

Step 1: Test Case ID

The first thing you need to do is write the test case ID. The ID is automatically assigned by the test management software and is unique to each test case.

Step 2: Test Case Description

The next stage is the test case description. Here, you’ll need to write what unit, feature, or function is being tested. In this case, you can write, “Check customer login with valid data”.

Step 3: Assumptions and Preconditions

This refers to the conditions that must be met to carry out the test. In this case, you’ll need to mention that a valid account is required for logging in.

Step 4: Test Steps

These are the steps required to carry out the test. For example-

  1. Open the email server webpage (URL)
  2. Enter User ID
  3. Enter Password
  4. Click “Enter” or “Login” button

Step 5: Test Data

This refers to the values and variables in the test case. In this example, it is the username and password of the account.

Step 6: Expected Result

This is the result expected after carrying out the test case. The goal of this test case is to ensure a successful login.

Step 7: Actual Result and Post-Condition

The actual result is the status of the test case. It is compared with the expected result. In this case, the user will either be successfully logged in or not. Post-condition refers to what happens after the test is carried out. In this scenario, the user will be redirected to the inbox.

Step 8: Pass or Fail

This refers to whether the execution of the test case leads to the expected result. If it meets the expected result then it can be considered a “pass’, and if it doesn’t, then a “fail”.

Unit Test VS Integration Test

The main difference between a unit test and an integration test is that a unit test is white-box testing whereas an integration test is black-box testing. Also, a unit test checks a single module while an integration test checks a group of two or more modules.

Compared to integration testing, unit testing is a quicker process with low maintenance because it doesn’t require any external resources, such as database and software components. A developer can easily write code and execute the test. Not to mention, unit test saves money as it allows developers to find errors in the early stage of development.

On the other hand, integration testing is a slow process because it requires the installation of dependencies, like hardware. Plus, it takes a lot of time to find bugs, and fixing them can be expensive. It is also difficult to write code for integration testing. Yet, it offers more code coverage necessary to check the entire system.

It’s worth noting that neither unit testing nor integration testing holds more importance than the other. Both tests should be performed during the development process to ensure there are no defects in the software.

Frequently Asked Questions

What is the purpose of a unit test?

The main purpose of unit testing is to isolate the code of a specific function to determine whether it works as expected. It is the first stage of testing software, and usually, developers perform the test. By running unit tests, developers can identify errors and fix them early before the software undergoes overall system testing.

Who performs unit testing?

Unit tests are typically performed by developers as they have written the code and have knowledge about the software’s internal structure. The test also provides feedback to developers on whether newly-developed features are functioning correctly or not.

By performing unit tests, developers can focus on improving the software quality.

Is unit testing part of QA?

Unit testing is a white-box testing technique, which means verification of the internal structure of the software is required. In this case, only the developer is involved as they have written the code and is familiar with the software’s internal structure.

On the other hand, the QA team is responsible for executing integration tests to reveal the errors that weren’t present during unit testing.  Integration testing is a black-box testing technique, which means it doesn’t require knowledge about the internal structure of software.

Wrapping Up

Unit testing is the first and crucial stage in software testing. It helps with identifying errors in every isolated component. Without performing a unit test, developers will face difficulty with bug identification later on in the software development process. Not only that but also fixing the errors can be expensive.

Rahnuma Tasnim

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top