OK, let's unpack this. Have you ever felt, you know,
just swamped by information, trying to really get a handle on
something new quickly but also properly?
Well, that's exactly why we do what we do here on the deep
dive. Our whole mission is to sort of
cut through the noise, pull out the really important stuff from
different sources and hopefully give you that aha moment.
Today we're diving into something pretty crucial.
If you're into software development or really just
building things that actually work reliably.
Unit testing. This deep dive is based on some
really interesting bits from Software engineering, a modern
approach by Marco Tulio Valente. We're going to explore why unit
tests are like everywhere now, and how they help make sure
software is up to scratch. Yeah.
And if we kind of step back for a second before we get into the,
you know, the nuts and bolts of unit testing itself, it helps to
remember what we're fighting against, so to speak, defects,
bugs, basically times when the code doesn't do what it's
supposed to do, and failures. That's when that buggy code
actually runs and causes a problem.
Unit tests are what one of our best tools for catching those
issues early on, right? So that brings us straight to
section 8.2 in the book, focusing specifically on unit
testing. Let's dig in.
What exactly are unit tests? What's really fascinating here,
I think, is how clearly the source defines them.
Unit tests are automated tests, OK, and they focus on these
small units of code, usually classes.
But the key insight, the really important bit, is that these
units are tested in isolation, completely separate from the
rest of the system. Isolation.
Yeah. So a unit test at its heart,
it's just a little program that calls methods from a class and
then checks, you know, did it get the result that expected?
And the structure of a system that uses unit tests.
It sounds quite neat. The book shows it right.
You've got your main code. Exactly.
Your main classes doing the actual work, filling the
requirements and then totally separate you have this other set
of test programs. Glue separation.
I like that. And this separation it brings up
something interesting. The source shows this figure
right with N classes and M tests, and it's not one to one.
Oh right, so not every class gets exactly 1 test.
Not at all. You might have one really
critical class, maybe it handles payments or something.
And it might have, I don't know, 1020 unit tests hitting it from
different angles, different scenarios.
And then conversely, you might have some simple classes, maybe
just data holders with very few tests, or maybe none if they're
super trivial or tested indirectly.
So it's flexible. It depends on what the code
does. Precisely.
That visual really shows it's about focusing effort where it
matters most. Complexity importance.
OK, that makes sense. So we know what they are testing
small bits in isolation. But how do developers actually,
you know, do this? They don't just write them a
notepad, right? No, definitely not.
You use specialized frameworks, tools built just for this job.
And the most famous family of these frameworks is called X
Unit. The X is just a placeholder,
really. It stands for whatever language
you're using. X Unit.
Yeah. It's got a history, goes back to
the late 80s, actually. A guy named Kent Beck made the
first one unit for a language called Small Talk.
Wow. OK, so it's been around a while.
It has, and maybe the one people know best today, especially in
the Java world, is J Unit. J Unit, Yeah, I've heard of that
one. So the first version of J Unit
Kent Beck again, along with Eric Gamma.
They apparently hammered it out on a plane trip back in 97.
No way on a plane. That's the story kind of cool,
right? Shows you can do when you're
focused I guess. Definitely.
So these frameworks J unit X unit, they're available for lots
of languages. Oh yeah, that's the huge
advantage. Pretty much any mainstream
language you can think of. Java, Python, C#, JavaScript,
Ruby, you name it. It's got an X unit style
framework, which means developers don't have to learn
some whole new testing language. They write the tests in the same
language they're building the system in.
Uses all the same skills, same tools.
Makes it much easier to adopt. Right, seamless integration.
That's smart. So to make this a bit more real,
the source uses an example, doesn't it?
A stack class. It does a classic data
structure, the stack you probably remember, it's like a,
well, a stack of plates. Last in, first out Ifo.
Exactly. You can push things onto the
top, pop them off the top, check the size, see if it is empty.
Simple stuff, and it also has this specific rule.
If you try to pop from an empty stack, it's supposed to throw an
error an empty stack exception. Simple example but good for
showing the testing process. And when you use J unit, there
are conventions little rules to follow.
Like the test class is usually named after the class it tests,
but with test on the end. So stack class gets a stack test
class. Makes sense, Easy to find.
And the methods inside stack test that actually do the
testing, they also have rules. They usually start with test
like test is empty or test push. They need to be public, no
parameters. And critically, they have this
at Test thing right before them. An annotation.
An annotation like A tag? Yeah, exactly like A tag.
It's how you tell June it. Hey, this method right here.
Run it as a test. Got it.
So what is one of these test something methods actually do
inside? Well, a typical unit test method
follows this nice clean pattern. Three steps basically.
First, you set things up. Create the object you're
testing. This is something that's called
setting up the fixture for the stack.
You just create a new stack instance stack, my stack?
Who's that? Something like that.
OK, step. One create the thing to test.
Step 2. You call the method you're
interested in like you'd call my stack dot is empty.
Perform the. Action step three.
Check the result. Exactly step three, verify the
result. You use special assert commands
provided by JUnit. There are lots of them, like
assert true, assert equals assert NOT NULL.
So for is empty. On a brand new stack, you'd use
assert TRUE. My stack dot is empty, so you're
asserting. I expect this to be true.
OK, setup ACT assert, that's pretty clear.
And running these tests you mentioned the IDE.
Helps. Yeah, your development
environment, your IDE makes this super easy.
You don't run the whole application, there's usually
just a right click option run as test or something similar.
It finds all those at Test methods and just runs them super
quick. And when they pav.
You get a nice clean output green bar.
Usually it'll say something like 15 tests run, zero failure, 0
errors, and it tells you how fast it was, often just
milliseconds. Milliseconds.
Wow. Yeah, that speed is huge.
It means you can run these tests constantly while you're coding,
get feedback almost instantly if you break something, OK.
But what about when things go wrong?
The source gives an example of a bug, right?
Like if the stack size started at 1 instead of 0.
Wait, a subtle bug? Maybe someone type size equal 1
instead of ize equals 0 when initializing the stack O.
Now, if you create a new stack and immediately call Waze emty,
it's going to return false because it thinks there's one
item in there, even though there isn't.
And the test that assert true my stack is empty.
That test would fail. Unit calls this a failure
specifically meaning an assertion didn't hold true.
The result wasn't what you expected.
So you get a red bar instead of green.
You bet. Red bar big failure text.
Yeah, and crucially, you get an error message like assertion
failed error. It'll tell you exactly which
assertion failed, what it expected true, and what it
actually got false. So it points you right to the
problem. Directly.
That immediate, specific feedback is incredibly powerful
for fixing bugs quickly. The source then shows a more
fleshed out stack test class right with more tests.
Yeah, it shows examples like test note empty stack checking
it's not empty after pushing, test size stack checking the
size after pushes, test push pop stack, making sure pushing then
popping get you back the same item, just covering more bases.
And there was something about setting up at before each.
Ah yes, that's a really useful 1.
You can write a method often called in it or setup and put
the app before each annotation on it.
What Joe Unit does then is it runs that setup method
automatically before it runs every single at Test method in
the class. Oh OK, so instead of creating a
new stack inside each test method.
You can do it once in the app before each method.
It guarantees every test starts with a fresh identical stack,
and since yeah, no interference between tests really important
for reliable results. It avoids repeating that setup
code everywhere too. That's clever.
Keeps things clean. Definitely.
So the whole JUnit process is basically find a test class,
then for every at Test method inside it make a new instance of
the test class. Run any app before each method.
Run the at Test method itself. Repeat isolation and consistency
all. The way and one last thing,
testing for expected errors like that empty stack exception.
Right, you need to test that too.
If the code is supposed to throw an exception under certain
conditions, you need to verify that it does June at 5, which
the source refers to. Version 5 to 10 specifically has
a nice way to do this using a cert throws.
How does that work? You basically tell it I expect
this specific exception like empty stack exception dot class
to be thrown when this piece of code runs.
You often provide that piece of code as a little inline function
of Lambda. If the runs and throws exactly
that exception, the test passes. If it throws nothing or throws a
different exception, the test fails.
Got it. So you can even test the error
handling. That's pretty comprehensive.
It really aims to be. You want confidence that your
code works correctly in normal situations and handles errors
properly. So wrapping up then, we've taken
this deep dive into unit testing.
We've seen it's about testing small isolated pieces of code.
Using frameworks like JNET following conventions like
naming and annotations. Running tests quickly and
getting immediate feedback, especially when things fail.
And using features like at before each for clean setup and
assert throws for error checking.
It really paints a picture of how crucial this is for building
solid software. Absolutely that focus on
automated testing right down at the smallest level the unit.
It's just fundamental these days for building anything complex
and reliable. It builds confidence and quality
from the ground U. Well, thank you for joining us
on this Dee dive.