Welcome back to the Deep Dive. Today we're going to try and cut
through some of the jargon around a really vital concept in
software development unit testing.
Yeah, it's a term you hear thrown around a lot.
Exactly. You've probably heard it, but
what does it actually mean? Why is it so important?
And, you know, how do the big tech companies really use it
day-to-day? Good questions.
It's easy to see it as just like a technical detail, right?
So our goal today is to give you a shortcut to understanding it
better. We're leaning on software
Engineering, a Modern Approach by Marco Tulio Valente.
It's a great source for this. We'll start with the basics, the
definitions, then we'll get into the timing.
When should you actually write these tests?
And finally, we'll unpack the benefits, why it actually
matters. And I think connecting it to the
bigger picture, it's really fundamental if you want to build
software that's robust, you know, reliable stuff that
actually works for users without constant headaches.
The real question is, how do we make sure complex systems are
high quality and maintainable? Unit testing is a big piece of
that puzzle. It turns theory into practice.
Well put. OK, so let's start where the
source does Section 8, point 2.1, laying out some key
definitions. We need these building blocks
first. Makes sense.
First up, test method. What is that really?
Well, it's basically the smallest piece of a unit test.
Usually it's a method in your code marked with something like
a test, you know, in frameworks like Joint, right?
And its whole job is to check one tiny specific bit of
functionality, right? Like looking at one specific
behavior under a microscope to make sure it does exactly what
you expect. Very precise.
And building on that, you have the fixture.
This is about setting the stage right.
All the programs state the data, the objects, whatever setup is
needed before your test method or maybe several test methods
can even run. OK, so the starting conditions.
Exactly. And the name fixture, it's kind
of interesting. The source points out it
actually comes from manufacturing.
Oh, really? Yeah.
Like a physical jig or tool that holds a workpiece steady while
it's being worked on in code. The fixture sort of fixes the
state, sets up that consistent, controlled environment so your
test results are reliable. Without a good fixture, things
can get unpredictable. That manufacturing analogy
actually makes a lot of sense. OK, next term test case.
Now the source mentions G unit 5 point Nella specifically here in
June. It a test case is basically a
class right? A container that holds a bunch
of related test methods. That's it.
The name itself, Test Case, is apparently a bit historical from
older Joe Unit versions where you inherited from a test case
class. But today think of it as just a
logical grouping, like all the tests for your user login class
might live inside a user login test class.
That class is the test case. Makes sense.
It keeps things organized and that leads naturally to test
suite. Suite sounds like more than one.
Exactly. A test suite is just a
collection of these test cases. You group several test cases
together, maybe all the tests for a whole feature or a module,
and the testing runs them all as one batch.
So you can check a larger part of the system all at once.
Precisely, it gives you that broader automated check on the
overall health of that section of code.
Got it. And one more key term here,
though it's a bit broader. System under test.
Yeah, SUT. Ah yes, AC.
This just means whatever specific piece of code you're
actually testing right now. Could be one method, could be a
whole class, maybe a small component.
Yeah, it's the target. You'll also hear people call it
production code. Right, production code.
Because it's the real code you're building the stuff that's
supposed to eventually go live. Defining your SUT clearly is
pretty important. It sets the scope for your test.
Absolutely. OK, so we've got those
definitions nailed down. Test method fixture, Test case,
Test suite, SUT. But knowing what they are is one
thing. The really practical question is
when do you write them? Yeah, the timing is crucial, and
there are really 2 main schools of thought here.
The first one, maybe the most common, is writing tests after
you've built a small bit of functionality.
So you write some code, maybe a method or two, and then right
away you write the test to prove that code works.
So it's code, then test, then more code, then more test, like
a cycle. Exactly.
A little loop code, a bit test it, repeat.
You get constant feedback as you go.
OK. That sounds logical.
What's the other way? The other way is, well, it's
kind of a paradigm shift for some people.
It's called Test Driven Development or TDD.
TDD right? Are they?
With TDD, you flip it completely.
You write the test first, before you write any of the actual
production code that the test is for.
Wait, so you write a test for code that doesn't exist yet?
Yep. And naturally that test is going
to fail, right? Because there's nothing in there
to make it pass. That's the red light in the TDD
cycle. Red because it fails OK.
Then only then do you write the absolute minimum amount of
production code needed to make that specific failing test pass
just enough to get the green light OK.
Red to green. And once it's green, you can
clean up the code refactor knowing your test will instantly
tell you if you broke anything. That's the refactor step.
So it's this constant red green refactor cycle.
That sounds disciplined. Writing the test first forces
you to think about the requirements upfront, I guess.
Precisely, it forces clarity about what the code should do
before you write it. Now, the source mentioned
something really interesting, especially if you've ever, you
know, pulled your hair out over a bug.
Yes, bug fixing. It is a really good time to
write a test is when you find a bug.
The idea is, before you even try to fix it, write a new test that
specifically makes the bug happen.
Reproduces the failure scenario. Exactly.
That test will fail, obviously, and you go fix the bug.
And if you fixed it right, that test you just wrote should now
pass. And the beauty is that test
stays in your test suite forever.
Right. It becomes like a permanent
guard against that specific bug ever coming back.
It's way better than just sticking in temporary print
statements to debug, you know? Oh totally, those system dot out
print and calls, they get removed.
The test is a lasting asset. It prevents regressions for that
specific issue. So that's a great tactic.
Now what about what not to do regarding timing?
Well, the big no no, according to the source and just general
experience, is leaving testing until the very end.
Like saving it all up for the end of a project or the end of a
Sprint. Kind of like how things used to
happen in older waterfall models.
Why is that so bad? Seems like you'd have a whole
picture then. The problem is, reality hits.
You're rushing to finish. New features are demanding
attention because the system looks like it's working, and the
tests either get done hastily and poorly, or worse, they just
don't get written at all. Quality suffers.
OK, short changed at the end. Yeah, and this ties into another
point. Who should actually write these
tests? Good question.
A separate QA team. The source strongly recommends
against that. Actually, the developer who
writes the production code for a class should also write its unit
tests. Really.
Why is that? Because they have the deepest
just understanding of how that code is supposed to work.
It's edge cases where it might break.
Outsourcing it or giving it to another team, you lose that
intimate knowledge. Keeping it together fosters
ownership and usually leads to better, more meaningful tests.
OK, that makes sense. Developer ownership for quality,
right? All right, so we've got the
definitions. We've talked about when to write
tests, ideally early and often, maybe TDD, definitely when
fixing bugs and not at the very end.
Now, the payoff. Why bother with all this?
What are the real benefits for, you know, the project, the
users, the business? This is where it really clicks.
I think the number one benefit, the most obvious one, is
catching bugs early, way before the code gets out into the.
Wild and early means cheaper to fix, right?
Massively cheaper. Think about fixing a typo on a
blueprint versus recalling thousands of cars.
Finding a bug with a unit test during development costs,
relatively speaking, almost nothing.
Finding that same bug after a lease?
That can cost a fortune not just in fixing it, but in lost
reputation, user trust, support, calls, everything.
Yeah, OK. That's a huge financial and
reputational driver. Absolutely, it's like the
cheapest insurance policy you can buy for your software
quality. OK, so catching new bugs early,
what else? The other huge one is acting as
a safety net against regression. Regressions.
That's when you fix something or add a new feature and it
accidentally breaks something else.
That used to work, right? Exactly.
That code regresses goes backward in quality because a
change had unintended side effects.
It's incredibly common in complex systems.
In frustrating. Totally.
But good unit tests are your defense here.
After you make any change a fix, a new future, even just cleaning
up code, you run your whole test suite.
If you accidentally broke something elsewhere, even in a
totally unrelated part of the code, a test over there will
fail. So it flags the collateral
damage immediately. Immediately before it gets
checked in, before it affects anyone else.
It gives developers confidence to make changes, to refactor, to
improve the code, because they know they have this automated
system constantly watching their back.
That sounds incredibly valuable, a safety net.
It really is. And there's another benefit may
be less obvious. The source mentions
documentation. Yes, this is often overlooked.
Unit tests act as living executable documentation for
your code. How so?
Well, think about trying to understand a piece of code you
didn't write or haven't seen in six months.
Instead of just reading the code itself or relying on potentially
outdated comments, you can look at the tests for that code.
The tests show you how the code is intended to be used.
What inputs does it expect? What should the output look
like? How does it handle weird edge
cases or errors? The tests demonstrate the
intended behavior in concrete, runnable examples.
So the tests are like examples of how to use the code
correctly. Exactly.
The source even suggests that before you start maintaining
some code, you should read its tests first.
It gives you a functional specification.
Living documentation. I like that.
OK, so these benefits sound great in theory.
Early bud catches regression safety net documentation.
But is this actually, you know, done in the real world, or is it
just academic? Oh, it's very much real world.
The source points out that unit testing is probably the most
impactful and widely adopted practice that came out of agile
methodologies. Tons of companies, big and
small, rely heavily on unit tests.
Any specific examples? Yeah, the source gives a couple
of big ones. Google for instance.
OK, what? Do they do at Google?
Unit testing is like baked into the culture.
It's expected that all production code has unit tests.
Their code review tools actually flag code if someone tries to
submit it without corresponding tests.
Wow, so it's enforced systemically?
Seriously enforced, it shows a massive commitment to quality
control right at the source. OK, Google's a big one.
Any others? Facebook or Meta now is another
example. Their engineers write unit tests
for their new code standard practice.
But critically, all code, before it can be committed and pushed
into the main code base, must automatically pass the entire
accumulated suite of progression tests.
So it's part of the pipeline. You literally can't merge your
code if it breaks existing tests.
Exactly. It's built right into their
workflow. Imagine the scale of their code
and how many changes happen daily.
That automated safety net is essential for them to move fast
without constantly breaking things for billions of users.
That makes total sense. You need that automation at
scale. You really do.
OK, so let's wrap this U. We've kind of unpacked the core
ideas, right? We looked at the definitions,
test method, fixture, test case, test suite, SUT.
We talked about when to write tests, ideally continuously.
TDD is an option definitely for bugs, not at the end, and we've
seen the huge benefits. Yeah, catching bugs early,
preventing those painful regressions and even acting as
useful up to date documentation it.
Really makes it clear why this isn't just a nice to have, yeah,
but pretty fundamental in modern software development, and why
places like Google and Meta build it right into their core
processes. Couldn't agree more.
Well, thank you for joining us on this deep dive.
We really hope this gave you a much clearer picture of unit
testing and why it matters. Thank you for diving in with us.