Introduction to Automated Testing: Building Reliable Code
Learn the essentials of unit testing to improve code quality. Create a simple Python script and build a test suite to automate your verification process.
Previously in this course, we covered workflow syntax deep dive. Now that you can execute arbitrary commands in your pipeline, it's time to ensure that the code you're running actually works.
In the world of professional software engineering, manual verification is the enemy of velocity. You cannot afford to open a browser and click through every feature every time you change a line of code. This lesson focuses on unit testing, the practice of verifying the smallest testable parts of your application in isolation.
Why Unit Testing Matters for Code Quality
At its core, unit testing is about feedback. If you make a mistake, you want to know about it seconds after saving your file, not hours later when a user reports a crash. By writing tests, you are essentially creating a safety net. This net allows you to refactor, upgrade dependencies, and add features with the confidence that you haven't broken existing functionality.
When we talk about automation in CI/CD, we aren't just talking about running a script; we are talking about running a validation suite that acts as a gatekeeper. If the tests don't pass, the build doesn't move forward.
Creating Your First Application
Let's start by creating a simple calculator script. It’s a classic example because it’s easy to verify. Create a file named calculator.py in your project folder:
PYTHON# calculator.py def add(a, b): return a + b def subtract(a, b): return a - b
This is our "production" code. It’s clean, modular, and does exactly one thing. Note how we avoided putting print statements or complex logic inside the functions—this makes them "pure" and easy to test.
Writing the Test Suite
To test this, we’ll use Python’s built-in unittest framework. It’s perfect for beginners because it requires no extra installation. Create a file named test_calculator.py:
PYTHON# test_calculator.py import unittest from calculator import add, subtract class TestCalculator(unittest.TestCase): def test_add(self): self.assertEqual(add(1, 2), 3) self.assertEqual(add(-1, 1), 0) def test_subtract(self): self.assertEqual(subtract(10, 5), 5) self.assertEqual(subtract(0, 5), -5) if __name__ == CE9178">'__main__': unittest.main()
Running Your Tests Locally
Before we put this into GitHub Actions, verify it works on your machine. Open your terminal and run:
Bashpython3 test_calculator.py
You should see an output like OK. This confirms your tests passed. If you change a value in the assertEqual check, you will see a failure trace. This "red-green" cycle—where you see a test fail, then fix the code to make it pass—is the heartbeat of modern development.
Hands-on Exercise
- Modify the code: Open
calculator.pyand add amultiply(a, b)function. - Add a test: Update
test_calculator.pyto include a new methodtest_multiplythat asserts the result ofmultiply(3, 4)is12. - Run again: Execute
python3 test_calculator.pyto ensure your new test passes.
Common Pitfalls
- Testing Implementation, Not Behavior: Don't write tests that check how a function works (e.g., checking internal variable names). Test what it returns given specific inputs.
- The "Slow" Test: Unit tests should be lightning fast. If your test needs to hit a database or a live API, it isn't a unit test—it's an integration test. Keep your unit tests focused on pure logic.
- Ignoring Failure: Never ignore a failing test. As noted in our discussion on technical debt, a failing test is a "broken window." Fix it immediately, or developers will stop trusting the test suite entirely.
FAQ
Q: Do I need a specific framework?
A: Not for learning. Python’s unittest or Node's assert module is fine. As you scale, you might explore pytest for Python or Jest for Node.js, as seen in this guide on testing with Jest.
Q: How many tests should I write? A: Focus on "happy paths" (normal inputs) and "edge cases" (like dividing by zero or empty strings). Aim for high coverage, but prioritize testing the logic that is most likely to break.
Recap
We’ve moved from just running scripts to validating them. By isolating logic in calculator.py and verifying it with test_calculator.py, you've established the foundation for automated quality control. In the next lesson, we will wire this into our CI pipeline to ensure these tests run automatically every time you commit code.
Up next: Running Tests in CI
Work with me

CI/CD Pipeline & Docker Containerization
Ship with confidence: automated CI/CD pipelines and Docker setups so every push is tested and deployed — no more manual, error-prone releases.

AI Automation & Agentic Workflow Development
Automate the repetitive work eating your time — content pipelines, data workflows, and agentic AI tasks that run themselves.
