Types of software testing: a practical map for teams that ship
The main types of software testing explained: functional vs non-functional, manual vs automated, when to use each, the testing pyramid, and a real workflow.

Ask five engineers to list the types of software testing and you get five different lists, half of them contradicting each other. Some talk about unit and integration tests. Some talk about performance and security. Some talk about manual versus automated. They are all right, because those are different ways of slicing the same pie. The confusion comes from mixing the slices.
This guide sorts it out. We will map the main types of software testing along the axes that actually matter, functional versus non-functional, the level a test runs at, and manual versus automated. Then we cover when each type earns its place, where the testing pyramid fits, and what a real testing workflow looks like on a shipping product. By the end you should be able to look at any test and know exactly which bucket it belongs in and why it exists.
We build production apps at Zarle, so this is written from the side that has to keep them running, not from a textbook.
The two big families: functional and non-functional
Almost every kind of test falls into one of two families. Getting this split clear first makes the rest easy.
Functional testing asks a simple question: does the feature do what it is supposed to do? You give it an input, you check the output, you confirm the behavior matches the requirement. Log in with the right password and you should get in. Add an item to a cart and the total should update. Functional tests do not care how fast it happened or whether it survives a thousand users, only that the result is correct.
Non-functional testing asks a different question: how well does it do it? Same login screen, but now you are asking whether it responds in under a second, whether it holds up when ten thousand people hit it at once, whether an attacker can slip past it, and whether a first-time user can figure it out without a manual. The feature can be perfectly correct and still fail every one of these.
Most teams over-invest in the first family and forget the second until something embarrassing happens in production. A checkout that works fine in a demo and collapses on launch day passed its functional tests and never got a load test. That gap is where a lot of the harder testing work comes from, and it is why the two families both need attention.
Functional testing, level by level
Functional testing gets organized by level, meaning how much of the system a test touches at once. This is the classic ladder, and it is worth knowing cold because it maps directly onto how you build.
Unit testing
Unit tests check one small piece of logic on its own, usually a single function or method. A discount calculator, a date formatter, a validation rule. They run in milliseconds, need no database or browser, and when one fails it points straight at the broken line. This is the foundation. When we build backend logic, the pricing and validation functions get unit tests before any screen exists, because catching a bad calculation here costs seconds instead of a support ticket later.
Integration testing
Two units can each work perfectly and still break the moment they talk to each other. Integration testing catches exactly that. It checks the seams: does the API actually write the order to the database, does an auth token unlock the right routes, does the payment service return what the order service expects. These are slower than unit tests because real dependencies are involved, but they catch the whole class of bugs that live between components rather than inside them.
System testing
System testing evaluates the complete, assembled application as one thing. Frontend, backend, database, and APIs all wired together in an environment close to production. Here you run full journeys the way they will really happen and confirm the whole machine behaves. System testing is where functional and non-functional checks often meet, since you can also look at performance and security once everything is running together.
Acceptance testing
Acceptance testing, usually user acceptance testing or UAT, is the last gate before release. The question shifts from "is it technically correct" to "can a real user actually get their job done, and is this what the business asked for." Real users or stakeholders run through real tasks. Something can pass every unit and integration test and still fail UAT because the flow, while correct, does not match what people actually need. When it passes, you ship.
Alongside these four levels sit a few functional types you will hear constantly:
- Smoke testing: a quick pass over core features to confirm a build is stable enough to test further. If the app will not even start, you stop here.
- Sanity testing: a narrow check after a small change to confirm that specific thing works before deeper testing.
- Regression testing: re-running existing tests after any change to make sure you did not break something that used to work. This is the workhorse, and it is the strongest argument for automation.
Non-functional testing, the part teams skip
The non-functional family is smaller in test count but often bigger in consequences. These are the types of software testing that decide whether your product survives contact with real usage.
Performance testing
Performance testing measures speed, responsiveness, and stability under a given workload. Load testing pushes expected traffic, stress testing pushes past the breaking point to see how it fails, and spike testing throws sudden surges at it. Fit Mom, a fitness app we built, crossed 10,000 downloads in its first month. A launch like that is exactly when performance testing stops being optional, because the failure mode is your best day turning into your worst.
Security testing
Security testing looks for the ways someone could get in or get data out that should not be possible. Injection attacks, broken authentication, exposed data, weak access rules. For anything touching payments, health records, or personal data, this is not a nice-to-have. Vulnerability scanning and penetration testing both live here.
Usability testing
Usability testing checks whether real people can use the thing without frustration. Can a new user find the signup, complete it, and understand what happened. This is judgment-heavy and hard to automate, which is why it stays largely a human job. A feature that is correct but confusing still loses users.
Compatibility testing
Compatibility testing confirms the software works across the browsers, devices, operating systems, and screen sizes your users actually have. A layout that looks perfect on the developer's laptop can be broken on an older Android phone. For consumer apps this matters enormously, since you do not control what hardware people show up with.
Functional vs non-functional at a glance
Here is the split in one view, since this is where most of the confusion lives.
| Dimension | Functional testing | Non-functional testing |
|---|---|---|
| Core question | Does it do the right thing? | How well does it do it? |
| Examples | Unit, integration, system, acceptance, smoke, regression | Performance, security, usability, compatibility |
| Based on | Business requirements | Quality attributes and expectations |
| Typical failure | Wrong result, broken flow | Slow, insecure, confusing, breaks on a device |
| Mostly caught by | Automated tests | Mix of tools and human judgment |
| When it bites | During use, per feature | Under load, under attack, at scale |
Neither family replaces the other. A product needs both, and knowing which types of software testing sit in each column is how you spot the gaps in your own coverage.
Manual versus automated: a different axis entirely
People treat manual and automated as another type of test, but it is not. It is a separate axis. Almost any of the types above can be run by hand or by a script. The real question is which approach fits which test.
Automate the tests that are stable, repetitive, and run often. Regression suites, core business logic, critical flows you check on every release, and past bug fixes so the same bug can never quietly return. A machine runs these on every commit without getting bored on the four-hundredth pass.
Keep humans on the tests that need judgment or change constantly. Exploratory testing, where the point is to poke around and find surprises. Usability, where you are judging whether something feels right. Brand-new features whose design is still shifting weekly, since automating a moving target wastes the effort.
A rough rule we use: if you would test something by hand more than three times, it probably deserves a script. If you would test it once and move on, writing the automation costs more than it saves. Manual and automated are not rivals. They cover different weaknesses.
Where the testing pyramid fits
The testing pyramid is the strategy that ties the functional levels together. Picture a triangle. The wide base is fast unit tests, the middle is integration tests, and the narrow top is slow end-to-end or system tests. You want many cheap fast tests at the bottom and few expensive slow ones at the top.
Teams that ignore this build what people call the ice cream cone, an upside-down pyramid stuffed with slow UI tests and almost no unit tests. Those suites take twenty minutes, fail for random reasons, and get switched off within a quarter. The pyramid holds because feedback speed matters. Cheap tests catch the obvious breaks in seconds, so the slow ones only run on code that already passed the basics. If you want to go deeper on the automated side of this, we wrote a full software test automation guide that covers tooling and CI in detail.
A real testing workflow
Here is roughly how the types of software testing sequence on an actual project, rather than as a flat list.
- A developer writes a feature and unit tests for its logic, running them locally in seconds.
- On every push, unit tests run first in CI because they fail fastest and cost nothing.
- Integration tests run next against a throwaway test database, confirming the seams hold.
- A focused set of end-to-end tests drives the critical journeys through the real app.
- Before a release, the team runs smoke and regression passes, plus performance and security checks on anything high-stakes.
- Real users or stakeholders run acceptance testing to confirm the release does the job.
- Only when all of that is green does the change deploy.
On Cheflobra, the food platform we built where chefs list dishes and customers order them, the flows that carry the business, sign-up, listing, and ordering, get end-to-end coverage that runs in CI on every change. The backend logic gets unit tests, the seams get integration tests, and load testing happens before anything that could bring traffic. The point is not test count. It is confidence that a bad deploy gets caught before a user ever sees it.
How to choose which types you actually need
You will not run every type of testing on every project, and you should not try. Match the effort to the risk.
- A throwaway prototype needs little more than smoke tests and a manual click-through.
- A long-lived product that changes often needs a strong unit and regression base, because the same flows get re-tested constantly.
- Anything handling money, health data, or a public launch needs real performance and security testing, not just functional passes.
- A consumer app on many devices needs compatibility testing that a private internal tool can skip.
The mistake is treating the full list as a checklist to complete. It is a menu. Pick the types of software testing that match what will actually hurt if it breaks, and spend your effort there.

Frequently asked questions
What are the main types of software testing?
They split into two families. Functional testing checks whether features do the right thing, and includes unit, integration, system, acceptance, smoke, and regression testing. Non-functional testing checks how well the software performs, covering performance, security, usability, and compatibility. A separate axis, manual versus automated, applies across both families.
What is the difference between functional and non-functional testing?
Functional testing asks whether the software behaves correctly against its requirements, like whether login works. Non-functional testing asks how well it behaves, like whether login is fast, secure, and easy to use under real conditions. A feature can be perfectly correct and still fail non-functional testing on speed or security.
What are the four levels of testing?
Unit, integration, system, and acceptance. Unit tests check one small piece of logic. Integration tests check that components work together. System testing evaluates the whole assembled application. Acceptance testing confirms real users can accomplish their tasks and the release meets business needs before it ships.
Should testing be manual or automated?
Both, for different jobs. Automate stable, repetitive tests that run often, like regression suites and core logic. Keep humans on exploratory testing, usability judgment, and features whose design is still changing. A useful rule: if you would test it by hand more than three times, it probably deserves automation.
What is the testing pyramid?
It is a strategy for balancing test types. Many fast unit tests form the wide base, fewer integration tests sit in the middle, and a small number of slow end-to-end tests sit at the top. It keeps feedback fast and suites reliable, avoiding the slow, flaky setups that teams eventually abandon.
Which types of software testing do I actually need?
Match testing to risk. Prototypes need little. Long-lived products need a solid unit and regression base. Anything touching payments, health data, or a big launch needs performance and security testing. Consumer apps on many devices need compatibility testing. Pick the types that hurt most if they break.
Build it tested from the start
The types of software testing are not a checklist to complete for its own sake. They are a map of the different ways your product can fail, functionally and non-functionally, and each type exists to catch one of them. Sort them by family and level, decide what to automate, keep the pyramid the right way up, and spend your testing effort where a failure would actually cost you.
If you want a product built with testing in the pipeline from day one, not bolted on after launch, talk to us about backend and cloud services. We are an in-house team that ships production apps and treats a green test suite as the baseline, not a luxury.


