What Is Unit Testing?
Unit tests are automated tests created by developers to verify that individual components of an application, known as units, are error-free and behave as expected.
Unit testing is an excellent first step for testing a complex applicationâdevelopers create unit tests for the smallest testable units, and verify that they are working in isolation. Then they can add integration and acceptance tests to verify that these units are working well together and satisfying user requirements.
A unit can be a function, a procedure, an object, or an entire module. When building unit tests for object-oriented programming (OOP), the unit of testing is typically a complete interface, such as a class or a single method.
In this article:
Unit Testing Techniques
Structural Unit Testing
Structural testing is a white box testing technique in which a developer designs test cases based on the internal structure of the code, in a white box approach. The approach requires identifying all possible paths through the code. The tester selects test case inputs, executes them, and determines the appropriate output.
Primary structural testing techniques include:
- Statement, branch, and path testingâeach statement, branch, or path in a program is executed by a test at least once. Statement testing is the most granular option.
- Conditional testingâallows a developer to selectively determine the path executed by a test, by executing code based on value comparisons.
- Expression testingâtests the application against different values of a regular expression.
Functional Unit Testing
Functional unit testing is a black box testing technique for testing the functionality of an application component.
Main functional techniques include:
- Input domain testingâtests the size and type of input objects and compares objects to equivalence classes.
- Boundary value analysisâtests are designed to check whether software correctly responds to inputs that go beyond boundary values.
- Syntax checkingâtests that check whether the software correctly interprets input syntax.
- Equivalent partitioningâa software testing technique that divides the input data of a software unit into data partitions, applying test cases to each partition.
Error-based Techniques
Error-based unit tests should preferably be built by the developers who originally designed the code. Techniques include:
- Fault seedingâputting known bugs into the code and testing until they are found.
- Mutation testingâchanging certain statements in the source code to see if the test code can detect errors. Mutation tests are expensive to run, especially in very large applications.
- Historical test dataâuses historical information from previous test case executions to calculate the priority of each test case.
Unit Testing Examples
Here are some examples of unit tests in different operating systems.
Unit Tests in Android
You can perform instrumented or local unit tests on Android devices. With instrumented tests, you build and install the app alongside a testing app (these are typically UI tests that launch and interact with the app). Local tests are typically small and focused, running on the host side (e.g., the development server).
You can build an instrumented test that interacts with the UI on an Android device. For example, you can use a code snippet to click on a âStartâ element and verify that it triggers a welcome message element:
// When the Start button is selected
onView(withText("Start"))
.perform(select())
// Then the Hello message appears
onView(withText("Hello"))
.check(matches(isDisplayed()))
Related content: Read our guide to unit testing in Android (coming soon)
Unit Tests in Angular
Angular unit tests can uncover various issues, including logic flaws and malfunctions, by isolating code snippets. Angular helps you write code to test an applicationâs functions in isolation. Angularâs main testing utility package is TestBed (the other is async).
You can perform a unit test by running the âbeforeEachâ block and then running a sequence of other blocks such as âitâ or âxitâ blocks. The other blocks must follow the âbeforeEachâ block but are otherwise independent.
For example, the first block in the âdescribeâ container is always âbeforeEachââyou can then run additional blocks to compile components and verify that the system creates the tested component. The second block might demonstrate the accessibility of the componentâs propertiesâonly the title property is added by default.
The following code will reveal if the componentâs title remains the same as the title you set:
it(`title should be 'example-unit-test'`, async(() => {
const fixture = TestBed.createComponent(ExampleComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('example-unit-test');
}));
You can use a third block to show how your test behaves in a browser environment. Once youâve created the testing component, the system calls an instance of your component to simulate how it runs on the browser. You can then access child elements of the rendered component by accessing its nativeElement object:
it('title should render in a h2 tag', async(() => {
const fixture = TestBed.createComponent(ExampleComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h2').textContent).toContain(âStart example-unit-test');
}));
Related content: Read our guide to unit testing in Angular (coming soon)
Unit Tests in Node.js
You can use the Node.js framework to execute server-side JavaScript. This open source platform supports the Mocha JavaScript testing framework (among others). You can use special Mocha keywords in the test API to indicate that your code is a unit test. For example, describe() indicates a group of test cases (arbitrarily nested), while it() indicates a single unit test.
Here is an example of a simple test suiting containing a single test case, using the Chai assertion library:
const {describe} = require('mocha');
const chai = require('chai');
describe('Example test suite:', function() {
it('2 === 2 should be true', function() {
chai(2 === 2);
});
});
The testâs output should confirm the it( function (in this case, 2 === 2 should be true) with a tick and indicate the passing time in milliseconds. You can use any assertion library, including the built-in Assert library (although this is not recommended).
Related content: Read our guide to unit testing in Node.js (coming soon)
Unit Tests in React
You can use the open source React Native framework to build and test mobile applications. React offers built-in Jest, a JavaScript test framework with a simple unit testing solution. Because Jest is usually pre-installed in most React Native applications, you only need to open the package.json file and set the Jest preset to React.
In this example, you create a sum function adding two numbersâthis should be a simple equation where you already know the answer. You import the sum function into the test file under the title ExampleSumTest.js:
const ExampleSum = require('./ExampleSum');
test('ExampleSum equals 4', () => {
expect(ExampleSum(2, 2).toBe(4);
});
The output should specify if the test passed, confirming the sum as the expected result, and specifying the passing time in milliseconds:
PASS ./ExampleSumTest.js
â ExampleSum equals 4 (5ms)
Related content: Read our guide to unit testing in React (coming soon)
Unit Testing with Bright
Bright is a developer-first Dynamic Application Security Testing (DAST) scanner, the first of its kind to integrate into unit testing, revolutionizing the ability to shift security testing even further left. You can now start to test every component / function at the speed of unit tests, baking security testing across development and CI/CD pipelines to minimize security and technical debt, by scanning early and often, spearheaded by developers. With NO false positives, start trusting your scanner when testing your applications and APIs (SOAP, REST, GraphQL), built for modern technologies and architectures. Sign up now for a free account and read our docs to learn more.
