Introduction
Unit-testing can be a scary term. It may produce thoughts of choosing from a multitude of test processes, best practices, and frameworks. However—at the same time—you may not even have a grasp on where to start with unit testing. In this article, we’ll define unit testing and add context with examples. This will allow you to see how unit-testing fits into the larger testing environment.
What is Unit Testing?
Some of us may remember that units are forms of measurement. It represents a fraction of the entire amount. Unit testing is dividing application code into units and writing tests for each unit. These tests are often independent of the other units in the code.
Unit tests are typically automated tests written and run by software developers to ensure that a section of an application (known as the “unit”) meets its design and behaves as intended.
Hamill, Paul (2004). Unit Test Frameworks: Tools for High-Quality Software Development. O’Reilly Media, Inc. (Wikipedia)
Unit testing can look different depending on how you decide to break down your code. You can divide it by class objects, functions, modules (files), etc. However, it’s an accepted practice that a unit test is only as big as the code’s purpose or requirements. There is a temptation to write tests that span multiple units.
Who Writes Unit Tests?
Unit tests are often written by developers. They are stored alongside the source code. Testing libraries help developers automatically run tests during development. Additionally, tests can be executed as part of a CI/CD pipeline. This is beneficial if the test suite takes a long time to run. Furthermore, it helps to prevent introducing bugs into production code.
Executing these tests as part of a CI/CD pipeline is done with automatic testing tools.
Unit tests ensure the low-level functionality of the code. However, what if you need to test that the code works together? In the next section, we’ll define other types of testing that suit applications at a higher level.
Types of Software Testing
Integration Testing
Integration testing […] is the phase in software testing in which individual software modules are combined and tested as a group.
SO/IEC/IEEE International Standard – Systems and software engineering. ISO/IEC/IEEE 24765:2010(E). 2010. pp. vol., no., pp.1–418, 15 Dec. 2010. (Wikipedia)
Integration testing combines the units of code to fulfill higher-level requirements. This type of testing is combined with other forms of testing.
Functional Testing
Application features are tested with functional tests. Functional testing is similar to integration testing because you are taking a larger slice of the application and checking whether it works as intended.
Functional testing is often performed by quality assurance (QA) agents that are unaware of how the software is implemented.
You can use tools like RapidAPI Testing to perform functional testing.
Regression Testing
According to Software Quality Assurance, Testing and Metrics, regression testing is done to ensure that existing features are not broken by new features. This is done by re-running functional tests.
Following the progression from unit tests to integration/functional testing, regression testing seeks to reduce changes that break existing features.
Unit Testing Frameworks
Over the years, strategies have been introduced to better test applications and APIs. Testing frameworks help people organize and develop their tests. Additionally, unit testing frameworks often pertain to specific programming languages. In this section, we’ll discuss general testing approaches and some test frameworks.
Test-Driven Development (TDD)
TDD is a “backward” way of building software. Many times (and still today) tests are written after the code is completed.
Test-driven development flips the process. First, you write tests to match requirements. Then, you write code that passes the tests and, hopefully, satisfies requirements.
A good place to start with TDD is with this conversation on the podcast Test & Code with Brian Okken.
Additionally, you can view best practices for TDD on Wikipedia by clicking here.
Behavior-Driven Development (BDD)
BDD emerged from TDD. It is similar in approach but adds:
“[…] ideas from domain-driven design and object-oriented analysis and design to provide software development and management teams with shared tools and a shared process to collaborate on software development.”
Bellware, Scott (June 2008). “Behavior-Driven Development”. Code Magazine. Archived from the original on 12 July 2012. (Wikipedia)
This approach draws similar comparisons to TDD that we saw when comparing unit-testing to functional testing. For example, developers perform unit testing when working with units of source code. QA performs functional testing by looking at features of the software.
BDD encourages collaboration and tooling across more people in a team while taking a higher-level view of the application. I would agree with the statement that BDD is a good approach when dealing with a complex user experience.
Jest
Jest is a common framework (library) to use in Javascript testing. It allows developers to create assertions that read like English. Furthermore, Jest provides a simple way to mock objects, functions, data, etc.
pytest
pytest is a mature full-featured Python testing tool that helps you write better programs.
Another language-specific framework, pytest is a common choice among Python developers looking to tool themselves for writing unit tests.
Many frameworks depend on your application or programming language. You can view an extensive list of unit testing frameworks here.
Examples of Unit Testing
Now that we have discussed the basics of unit-testing, and given some background to software testing in general, let’s explore some unit testing examples.
Setting up the environment for the examples below is beyond the scope of this article. Instead, these examples will only provide simple implementations of unit testing using ReactJS (a Javascript framework) and Python (a general-purpose programming language).
ReactJS
First, let’s look at unit testing in React using React Testing Library and Jest.
I have a <Blockquote />
component that renders an HTML blockquote
tag. I want to ensure that a cite attribute is rendered in the HTML if I pass a cite
prop to the component.
<Blockquote cite="example citation" /> // In the HTML we should see <blockquote cite="example citation"></blockquote>
Let’s imagine this component is a nicely designed blockquote with some added logic. However, it should retain citations when refactoring.
Now, I can create a test file that imports the component and runs an assertion.
import React from 'react'; import { render } from '@testing-library/react'; import Blockquote from './Blockquote' test('should have a cite attribute', () => { const anyQuote = "Hello world!"; const anyCite = "https://source.com"; const { getByText } = render(<Blockquote quote={anyQuote} cite={anyCite} />) const blockquoteEl = getByText(anyQuote); expect(blockquoteEl.getAttribute('cite')).toEqual(anyCite); })
My React project uses Jest, so in the terminal I execute $ npm run test
. This command runs the command jest -c jest.config.js --watchAll
.
Finally, in the terminal, I get the output:
As a developer, I can run the test to check my code as I am developing.
Python
Testing React is different than testing in Python. React is a front-end Javascript framework. Therefore, it’s rendered in the DOM.
Python can be used to build web apps, APIs, command-line interfaces, desktop applications, and scripts. This example will be small but demonstrates a basic unit test in Python.
First, I have created a function in parse_name.py
named parse_name
.
def parse_name(name): name_list = name.split(' ') return name_list[0] + " " + name_list[-1]
This function takes in a name string and returns the first and last items.
Next, I can create the test file named test_parse_name.py
.
from parse_name import parse_name def test_parse_name(): assert parse_name("Jarrett 'pytest' Retz") == "Jarrett Retz"
Finally, in a terminal (that has access to the pytest
library) I execute the command:
$ pytest Documents/test_parse_name.py
If the test is successful, I get the below output.
What About APIs?
You may wonder, can you create unit tests for APIs and API routes? It depends on your API. If the routes are highly independent of one another then I think it’s possible.
Related: What is API Testing?
You may have a Python API route that is connected to one function. Theoretically, you could set up unit testing from outside the source code and run basic assertions.
For example, the parse_name
function used in the previous section could exist inside of a larger micro-service internal API. Therefore, you could use an automated testing tool to run the tests.
Conclusion
Unit-testing is not a fixed practice in programming. More importantly, there is not only one way to do it. It’s best to explore the options available and try to fit them into your application. And remember to pay attention to best practices and anti-patterns.
I hope this article has helped you better understand unit testing. Thanks for reading!
FAQ
What is integration testing?
Integration testing combines the units of code to fulfill higher-level requirements.
What is unit testing?
Unit testing is dividing application code into units and writing tests for each unit. These tests are often independent of the other units in the code.
Who writes unit tests?
Unit tests are often written by developers. They are stored alongside the source code. Testing libraries help developers automatically run tests during development.
Leave a Reply