DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Any Version of the Test Pyramid Is a Misconception – Don’t Use Anyone
  • Continuous Integration for iOS and macOS: Low-Code Self-Hosted Runner for Xcode Project Automation
  • SSDL at a Glance
  • Testing Serverless Functions

Trending

  • The 4 R’s of Pipeline Reliability: Designing Data Systems That Last
  • Event-Driven Architectures: Designing Scalable and Resilient Cloud Solutions
  • Unlocking AI Coding Assistants Part 2: Generating Code
  • Evolution of Cloud Services for MCP/A2A Protocols in AI Agents
  1. DZone
  2. Testing, Deployment, and Maintenance
  3. Testing, Tools, and Frameworks
  4. Unit Testing: The Good, Bad, and Ugly

Unit Testing: The Good, Bad, and Ugly

We may not enjoy unit testing, but it's essential to software quality. Let's explore the importance and workings of unit testing.

By 
Ayush Prashar user avatar
Ayush Prashar
·
Sep. 04, 18 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
18.3K Views

Join the DZone community and get the full member experience.

Join For Free

Unit testing is common to all the code that we write. We all do it, so it's important to understand the most "looked-forward to" (sarcasm) aspect of development. However overlooked and underestimated, unit testing forms the most important part of any development cycle and hence it's worth delving into. So let's begin.

So the big question at hand is, what is unit testing?

"A unit test is an automated piece of code that invokes a unit of work in the system and then checks a single assumption about the behavior of that unit of work." — Roy Osherove

A fair definition, but let's break it down. I want to focus on two important constituents of this definition:

"invokes a unit of work.."

Here, a unit of work is a single logical use case of the system irrespective of its size. It could span a method, multiple methods, a class or even classes. All that matters is this combination achieves a single logical purpose.

"...checks a single assumption about the behavior of that unit of work."

A unit test case works with something specific about a functionality, it doesn't cover it entirely. It's a bad practice to create something called testAllThings and call every method in the namespace.

Another important aspect of a unit test is that it works with the use case in isolation. Which means it should not depend or be bothered by any external entity. So changing another part of the codebase should not affect a unit test case. Simply put, if you have a unit test case that doesn't run without a proper setup or malfunctions in the presence of one, you haven't written a unit test case.

Now before we dive further, let's first understand the need for a unit test. Why do we put in at least half as much time as we devote in development, on unit tests?"It helps us verify a functionality" one might say, and I won't disagree, it is an important thing to know what you have coded actually works. But however much we say it, one thing always bugs us.

It Slows Us Down

That same time could have been spent more productively on other activities, right? Wrong. And I'm not saying this out of thin air. According to a press release by TypeMock, which makes unit testing products, unit testing saves about 70-80% time in debugging. So in the long run, it saves time. Go figure!

In addition, unit testing offers great feedback on the modularity and design of your code. Whenever you're struggling to work with a class and method in order to test it, there is a design problem. Hence it's not only about making testing.

Now that we know what unit testing is and why one should do unit testing, let's look at some good practices.

Good Practices

  • Test cases should be small and isolated. As mentioned above, they should test something specific about the code.

  • Try keeping test to assertion ratio near to 1. It makes it easy to identify any assertion which has failed. Having multiple assertions can make it cumbersome to verify which assertion went rogue.

  • Always avoid test interdependence. Each test case should handle their own build up and tear down. Test runners don't generally run tests in any specified order. Thus, we can not assume anything based on the order in which we write the cases.

  • A test case approaches the behavioral aspect of the code. So it should be easily comprehensible in the sense that what we are testing and what to do in case of failure.

  • Mock as little as needed. Too many fakes create fragile tests which break when they code undergoes changes in production.

  • Avoid mocking chatty interfaces. Any change in the order of calling may break the test.

  • It should be independent of external factors. You must not require a setup to run a unit test.

  • We must maintain a clear naming convention in writing unit tests. This simply makes our code more comprehensible.

  • While working on a continuous integration build, always add the unit test cases to the build so that whenever one test case fails, the whole build fails thus leaving no exemptions.

Bad Practices

  • Using nondeterministic factors in the codebase: Such scenarios are difficult to test especially when they don't reproduce/hold a constant value on each rerun. Eg Using Time as an authentication measure in code which would vary at each moment and also in different time zones.

  • Using side-effecting methods: Testing these could be as difficult as testing methods with a nondeterministic factor in them. Poorly designed untestable code introduce unwarranted complexities.

  • Impurity is highly toxic: Method depending upon non-deterministic or side-effecting methods themselves become the same kind and in the end complicate the entire codebase. Considering the effect it may have on a real-life complex application, we may find ourselves trapped in codebase filled with antipatterns, secret dependencies and all sorts of unpleasant scenarios.

  • Mocking interfaces and classes outside the codebase: If you don't fully understand the proper usage of an interface, you should avoid mocking it. Rather you should wrap interaction with external API classes into specially created interfaces for the same purpose.

  • Working with the mutable global state: Method depending upon mutable global state not only requires you to consider the current value but also be updated about other codes that may have altered its value earlier. Hence it's advisable to avoid them.

This was a brief version of The Good, Bad and Ugly of Unit Testing. I hope it was of some help.

References:

  • Art of Unit Testing

  • Code Better

  • Methods & Tools

  • Stackify

unit test Test case Continuous Integration/Deployment

Published at DZone with permission of Ayush Prashar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Any Version of the Test Pyramid Is a Misconception – Don’t Use Anyone
  • Continuous Integration for iOS and macOS: Low-Code Self-Hosted Runner for Xcode Project Automation
  • SSDL at a Glance
  • Testing Serverless Functions

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!