Welcome to the Deep dive. Today we're getting into
something really fundamental in the tech world, the whole
practice of software testing. We're going to, you know, unpack
why it's basically essential these days, absolutely critical.
And our thinking today, it's guided by some great material.
Excerpts from Software Engineering a Modern Approach by
Marco Tulio Valente. A really solid source.
So the mission today, we want to look at how testing grew up
right from the old ways to agile and then really dig into
automated tests, especially using this this model called the
test pyramid. That pyramid's a great visual,
yeah. To kick things off, there's this
quote from the book that just jumps out.
Code without tests is bad code. I mean, that's quite a
statement, isn't it, it? Absolutely is.
And it's it's way more than just being catchy.
OK, The thing is, writing software, it's like building
something incredibly complex from the ground up.
I mean, software is one of those intricate things humans make.
So it's just naturally going to have flaws, inconsistencies,
bugs. So testing isn't just, you know,
checking things at the end. It's going to be part of the
building process itself. It's how you build in robustness
from the start instead of just fixing things when they break
later. So the quote isn't just being
dramatic, it's about engineering integrity.
Exactly. That's a perfect way to put it.
Engineering Integrity. OK, so if testing is so baked
into modern development, how did it used to be?
What was the the old way? Oh, it was a totally different
world really. Think traditional waterfall
development. OK, waterfall.
Testing was its own separate box, a distinct phase.
You do requirements analysis, design, coding, then you test.
After everything else was supposedly done, pretty much.
And it often wasn't even the developers doing it, you had
separate test teams. Right, the QA department.
Exactly, and a lot of what they did was manual, like literally
clipping through the application, typing stuff in,
looking at the screen to see if it was right.
Since slow it was. And the main goal was simple,
find the bugs before this thing gets out to real users before
production. OK, so that was the old way, but
then things changed. We talked about Agile a lot.
How did Agile just completely flip the script on testing?
Agile, yeah, it was a seismic shift for testing.
I mean fundamentally. How so?
Well, for starters, a huge chunk of testing became automated.
Developers started writing code whose whole job was to test
other code. So the code tests itself in a
way. Kind of, yeah.
Programs became self testable. That's a massive change.
Definite way. And because of that, tests were
only done after coding. You could actually write the
test before you even wrote the class it was supposed to test.
Whoa, OK. Test Driven Development, right?
That's part of it, yeah. And those big separate test
teams mostly gone or they handle very specialized stuff now.
So who does the test in? The developer, the person
writing the class, is now responsible for writing its
tests too. That makes sense responsibility
wise. It does, and testing took on new
jobs. It wasn't just finding bugs
anymore. Tests became like living
documentation for the code. Documentation.
Well, a good test shows you exactly how a piece of code is
supposed to be used and what it should do better than comments
sometimes. Interesting.
Plus, they're crucial for checking if a bug fix over here
accidentally broke something over there.
You know, regression testing. Right, Run the tests, make sure
everything still passes exactly. So.
Going back to that Michael Feathers quote, code without
tests is bad code in this agile world.
It's like if your code can't be easily tested, if it doesn't
have those automated tests, it's just not good quality.
Maybe even legacy code from day one you've.
Nailed it. That's precisely the modern
view. And this focus on automated
tests wasn't just like a nice to have, it became necessary.
Why necessary? Think about it, how could you
possibly manually test a complex system that's changing maybe
multiple times a day? Yeah, impossible.
It's way too slow. Humans make mistakes, it costs
fortune, and you have to do it every single time anything
changes. Yeah, automation was the only
way to keep up. Right.
OK. So automation is key.
And you mentioned the test pyramid earlier.
Our source calls it an interesting way to classify
these automated tests. Mike Kuhn's idea, Yeah.
Mike Kuhn originally proposed it.
It's a really, really helpful model.
It basically sorts tests based on how big of a piece they're
looking at their granularity. Granularity, OK.
It breaks automated tests down into three main layers, Unit
integration and end to end. Unit integration end to end,
right? And the pyramid shape isn't just
random, it tells you something about how many of each type you
should probably have. It guides the proportions.
OK, proportions are important, so let's start at the bottom,
the base of the pyramid. What's down there?
Down at the wide base, you've got unit tests.
Unit tests. These check the smallest
testable bits of your code. Usually that means a single
class, or maybe even just one method within a class.
OK, really small pieces. Exactly.
Yeah, and they test it completely alone, isolated from
everything else in the system. Isolated.
How do they do that? Often using things like mock
objects or stubs to pretend to be the other parts the class
might talk to. Got it.
And they're at the base because you should have the most of
these lots and lots. The general guideline like you
see in the source is maybe around 70% of your total
automated tests. 70% Wow. That's the vast majority.
Why so many? Because they have big
advantages. They're usually simple to write.
They run super fast, like thousands and seconds, and if
one fails you know exactly where the problem is.
Pinpoints the issue. Precisely.
They're like tiny little quality checks on every single
component. Before you even assemble the
machine they check. Does this specific function give
the right output for this specific input?
Makes sense. OK, base layer covered.
Moving up the pyramid, what's the next level?
In the middle we have integration tests.
Sometimes people call them service tests.
Integration tests. What do they integrate?
They check out different parts of your system work together, so
instead of just one class in isolation, an integration test
might involve several classes, maybe from different modules or
packages. OK, testing the connection.
Exactly. They often verify a specific
piece of functionality or a transaction that scans across
these components. They might even interact with
external things like hitting a real database or calling an
external API. OK, so less isolated now.
Much less isolated, and because they involve more moving parts,
maybe external systems, they naturally take longer to write
and definitely longer to run than unit tests.
And proportion wise. The recommendation is usually
around, say, 20% of your tests. Significantly fewer than unit
tests, but still a good chunk. 20% OK unit integration.
That brings us to the very top of the pyramid.
What's up there? At the pointy top you have end
to end tests. End to end, E to E.
Right. You might also hear them called
UI tests, User interface tests or sometimes system tests.
And what are they testing end to end?
They try to simulate a real user's journey through the
entire application as realistically as possible.
Like someone actually using the software.
Pretty much clicking buttons, filling out forms, navigating
between screens, the whole sequence of actions a user might
take to complete a task, logging and doing something complex,
logging out. OK, that sounds comprehensive.
It is. That's the goal, yeah, But
they're at the top, the smallest section, maybe only 10% of your
tests, for good reason. Why so few?
They're way more complex to set up and maintain, they take a
long time to run compared to the others, and crucially, they tend
to be. Brittle.
What does that mean?
It means they break easily, often for reasons unrelated to
actual bugs in the logic. Like what?
Like if someone just changes the layout of the user interface
slightly, moves a button, changes an ID, the test script
might fail even if the underlying functionality is
perfectly fine. So they need a lot of
maintenance. A lot.
That's why you want fewer of them, focusing them on the most
critical user paths. Got it.
That pyramid structure makes a lot more sense now, balancing
speed, scope, and stability. OK, one last thing from the
source that seems really important for just clear
communication. The difference between a defect
and a failure. Yes, this is a really useful
distinction. People often use bug for
everything but technically. Technically.
A defect or a bug is the actual mistake in the code.
It's where the code doesn't match its specification or
requirement. It's the flaw itself.
The error written down essentially.
Right, the incorrect line of code, the wrong logic.
Now a failure is what happens when that defective code
actually runs. And because it runs, the program
does something wrong. It produces an incorrect result
or crashes, or just behaves unexpectedly.
So the failure is the observable wrong thing.
Exactly. The defect is the hidden cause.
The failure is the visible symptom that occurs when the
defect gets triggered. You need the defect to be
executed to cause a failure. A defect is the cause, failure
is the effect. That's a great clarification.
Also, won't be on the same page, yeah.
Definitely. Wow, this has been quite the
deep dive today. We've really covered a lot, you
know, starting with why testing is just non negotiable now,
tracing that big shift from waterfall separate phase to
Agile's integrated automated way.
A huge transformation. And then breaking down the test
pyramid, unit tests at the base, integration in the middle and to
end at the top, and finally getting that clear distinction
between a defect and a failure. Absolutely.
I think the main thing to take away is how central this
automated layered testing approach is to building good
software today. It's not an add on, It's
fundamental to quality, speed and just making sure things
don't fall apart. Totally agree.
So here's a final thought for you, our listener to chew on.
We heard that modern software is becoming self testable, right?
And that tests also act as documentation for the production
code. If those things are true, what
else could that mean for how we actually create software?
Does it open up new the possibilities beyond just
sketching bugs? Could it change what we even
think it means for software to be, you know, done or truly
complete? Interesting question.
Something to think about. We'll leave it there for this
time. Thanks for joining us on the
Deep Dive.