Files
hpr-knowledge-base/hpr_transcripts/hpr4091.txt

267 lines
20 KiB
Plaintext
Raw Normal View History

Episode: 4091
Title: HPR4091: Test Driven Development Demo
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr4091/hpr4091.mp3
Transcribed: 2025-10-25 19:31:21
---
This is Hacker Public Radio episode 4,091 from Monday 8th of April 2024.
Today's show is entitled Test Driven Development Demo.
It is the 20th show of Norrist, and is about 27 minutes long.
It carries a clean flag.
The summary is Norrist uses Pytist to demonstrate TDD, with a Trivel HP R&F O-A.
So I've done a few episodes where I'll write something, some software and Python, and talk
a little bit about it.
At least a few times I've mentioned using Test Driven Development while I'm doing it.
So I thought I'd just give a quick example using a Tribule application about maybe kind
of demonstrating a method of doing Test Driven Development.
So my last episode was 4075, and I talked about making a Pomodoro timer using Circuit
Python, and in that episode I talked a lot about why I like to use Test Driven Development
or how it helps me, and I sort of explained what it is if you want to hear that or if
you missed it, you can go back and listen, 4075, but just as a quick refresher, what is
Test Driven Development, it's where you think about what you're going to do, what you want
your code to do, what you want your project to do, and before you write any code, you write
a test.
And you can do it in a little chunk, you don't have to test the whole application, but you
think about a small thing that you want your code to do, and you write a test for it, and
you run the test, and obviously the test is going to fail because you haven't written any
code yet.
So then you write the minimum code to get the test to pass, run the test again, see that
it works, and then optionally after you get the test passing, you can rewrite, rerun the
code, just make sure the test continues to pass while you're doing the rewrite.
So we're going to do our testing with a Python framework called PyTest, P-Y-T-E-S-T.
PyTest is just a framework for testing software, it's usually used to test other Python
projects, but it doesn't necessarily have to test Python, it can test anything that
returns an input.
And the good thing about PyTest is it's just Python, so the test is written in Python,
so if you understand, or if you know enough Python to write a script or something like that
in Python, then you probably know just enough Python to write the PyTest.
So it's easy to use if you already know a little bit of Python.
It makes heavy use of the Python assert statement, so in Python you can test that something is
true by using assert.
And I'll show it, I'll have examples later, but if you want to test a variable equals
one, you can just say assert this variable equals one.
And if it passes, it will, the script will continue, if it fails, the script will abort.
And then PyTest, if you use an assert statement, and it passes, your test passes, and if you
use an assert statement, your assert fails, obviously your test fails.
So PyTest automatically discovers tests, and it's not going to make a lot of sense right
now because I haven't even told you what test are or anything.
But whenever you go into a directory where your Python project is, you can just run the
command PyTest, just like that, you don't have to specify a file pass or anything.
And what it will do is it will look for files that start with the name test, and if
it finds one that will run it, or it will look for, it will look into the files and look
for functions, a Python function that starts with the name test, and it executes those.
So what we're going to do is we're going to make two files, one that contains the application
that we want to, our trivial application that we're going to be working on, and then
a separate file called test underscore something that we'll put our test in.
So let's say just as an example project, we want to write a Python script that will print
some summary information for the latest published HPR episode.
So let's say we want to print the title, the hosts or the correspondence, the date, and
the path to the audio file.
So if we want to print all this stuff out, we can click on a link and it will take us
to the MP3 or AUG or whatever for the file.
So we can plan ahead and think about what we might need to do that.
So in my mind, the easiest way to do that, and there's a couple ways to do it, but you
could scrape the website or something like that, but in my mind, that information is already
published for you in a format that's easy to parse in the RSS feed.
So what we need to do for our app is we need to figure out how to get the RSS feed, and
then we need to figure out how to parse the RSS feed, and we need to know what the URL
is.
Okay, so let's say our script that's going to pull down the information from the HPR
feed.
We'll name it hpr-unterscore-info.py, and then we'll make a test, another Python script
that's going to contain all our tests, and we'll name that test-unterscore-hpr-unterscore-info.py.
Now that's, I like to have my test, the name of the test file reference what it's going
to be testing.
That's not a requirement, just something I do, it seems to be convention, a lot of people
I've seen do it, but it's not a requirement, but it's kind of best practice that way.
If you have a bunch of files that start with test, you can just look at the file name and
know what it's doing.
Okay, so remember with test-driven development, before we even write code, we're going to
write our test.
So we'll create the file, test-unterscore-hpr-unterscore-info.py, and then we'll put one line in it, and
that one line will be import, space, hpr-unterscore-info.
That's it.
So remember, we're going to name our actual project, hpr-unterscore-info.
So in Python, and therefore in Pytest, when you want to reference some code that's in
a different file, use the import statement to do that.
So whenever we say import-hpr-info, what we're asking it to do is look for a file named
hpr-info, and so later we can reference variables or functions or other things that are in
that file to do the testing.
So we've got our test file with a single import statement in it.
Now we can run Pytest.
So again, when you run Pytest, you don't have to do anything, specify file pass or anything
like that.
As long as you're in the directory, it will find the file containing the test, if you
named it correctly.
So we just run the directory, we just run the tip command, Pytest, and we get an error.
The first error we get is module not found, no module named hpr-info.
So what it's telling you is it's trying to import hpr-info, but it can't because that
file doesn't exist.
So we've written our first test, our first test failed.
So we need to create the minimum code to get that test to pass.
And in this case, the minimum code to get that test to pass will be creating an empty file
named hpr-info.py.
So we'll just run the touch command and touch hpr-undescore-info.py.
Now we run Pytest again, it doesn't really output anything, it doesn't say that we passed
or failed, but it doesn't error.
So that's good, so we haven't really written a test, but we kind of did the minimum test
by importing a file that doesn't exist.
We ran the test, it failed, we created an empty file, ran the test again, it passed.
Congratulations, we're doing TDD.
What we've done is we have confirmed that Pytest, whenever we run Pytest without any file
pass or anything, we've confirmed it found the Pytest, underscore hpr-undescore-info.py.
Confirm that Pytest found that test file, and we've also confirmed that the test file
is trying to import hpr-info.py since that error went away when we created the file.
We know that it's looking in the correct place to do the testing.
So we'll start writing some tests, some actual software tests.
Before I do that, we're going to use the assert statement quite a bit, so just as a quick
review for the Python Asserts, you say assert, and then you give it a comparison.
So for example, you could say assert1 equals 1, obviously that's true, so that'll pass.
Something else you can do is you can say assert a specific function, and you can say assert
a specific function equals and then desired output.
So what that means is later when we want to test our hpr-info app, we can assert the output
of let's say we have a function that prints the hostname, we can say assert the hostname
function equals whatever we want it to be.
We can also use assert without a comparison operator, and what that does is just verifies
that something exists.
So if we say assert1, it would equal true, so that assert would pass.
The way we can use that is if we have, if we want to verify that something exists, then
we can say assert, let's say there's a dictionary that has some files, and we want to assert
that it has a specific key in there, we can just say assert dictionary.key, just to make
sure that that exists.
Okay, so remember one of the first things we actually need to do to figure out, you know,
to get the host information for the latest hpr episode, we need to know hpr-feed.
So let's let's try to test for that.
Let's try to test that we have at least some value for the hpr-feed.
So very simple test, we'll just say asserthprinfo.hpr-feed, and this is assuming that we're going
to add a variable later called hpr-feed.
So when you, the way you reference something that exists in a different module and Python,
as you put the module name, and then a dot, and then the object you're referencing.
So remember we imported hpr underscore info, that's going to be the script we're writing.
So we just write a simple test, asserthprinfo.hpr-feed, then we can run by test.
That test will fail because that the object, hprinfo.hpr-feed, doesn't exist yet.
So what we can do is we can add in our hpr-feed info, we can add at the very top of the file,
we can just put hpr-feed equals, and then whatever the value for the hpr-feed is.
And again, we can run by test, this time the test will pass because the hpr-feed variable
exists.
And we could, if we wanted to, we could even update the test to say, assert that the hprinfo.hpr-feed
equals whatever value we want it to be, let's see, if we wanted to be the ockfeed and p3-feed
or whatever, we could do that too.
So we could, we could test that it exists or we could test that it is a specific value.
And then now, in the, when we run by test, it will detect that we've written the test,
now we have, and so when we run by test, we can start running it with the dash v flag that
usually gives you a little more information.
But this time it will say, tell us that it found one test and that test passed.
Okay, so now let's plan a function that pulls the hpr-feed and returns some feed data.
And we want to test that we get a http200 whenever we pull the hpr-feed.
So in our test file, we can write a simple Python function named test underscore, get underscore,
show underscore data.
So we're testing if we can get the show data.
We can define show data equals, and then we're going to say show data equals hpr dot get show data.
So what that, what that means is it's going to try to execute a function in hpr underscore info
called get show data.
And so after we say show data equals, underneath that, we'll have an assert statement that says
show data dot status equals 200.
So what this means is we're going to run that function and then we're going to expect some
information back. Part of that information back is going to be the status.
And then when we're asserting that the status is going to equal 200.
So now we have another test.
We don't have any code yet, but that's okay.
We run pi test.
We get one test failed and one test passed.
So our first test is still passing, that's good, but our new test is failing.
That's also good because that's what we expect.
You know, part of doing test driven development this way is not just writing and checking
passing tests. It's also making sure that you have failing tests.
When you expect a test to fail, I'm going to imagine if we had written this now to test
that the result is a 200 and we ran the test, expecting it to fail and it passed.
We would know that there was something really, really off.
So part of the reason you run the test first is to ensure it fails.
That way you know that you're actually testing the right thing.
Okay, so now that we've written a test to
verify the status of the 200, we've verified that test fails.
Now we can write, again, the smallest amount of code to get that to pass.
So in this episode, I'm not going to review the specific Python code.
If you want to see the Python script that we're testing against,
kind of been its final result, as well as the test files and its final result.
All this stuff will be checked in to my GitLab and links in the show notes.
But for now, let's just say through the magic of me doing this two weeks ago, there's a function
that pulls down the HPR on feed, gets all the data, and returns it status, and the status is
200. So now we can run the test again, and through the magic of, again,
having done this a couple of weeks ago, passes. Now we have two tests passing.
Like I said, if you can always just run PyTest without any arguments,
but if you want some extra information, you can run PyTest with a dash V flag,
and it will show you each individual test, pass or failed, and it'll also give you a percentage.
Right now we have two tests, so when one passes, that's 50% when the second one passes,
that's 100%. But you can imagine that would be more useful if you have a lot of tests.
Okay, so now that we have the feed, and we can assert that we're getting a good result
from pulling the feed, let's see if we can figure out if we can get the first episode.
So in the HPR underscore info script, we're going to use something called feed parser,
Python library called feed parser, and what it does is it returns data as Python dictionaries.
So what we want to do is we want to test that we can create a function called get latest entry,
and that it will return a dictionary that has a title and a published date.
So we'll write a new function in our test file called test underscore get latest entry,
and then we'll say latest entry equals HPR info dot get latest entry. So this is assuming
that we're going to write a function called get latest entry, and then we're going to assume
that that function returns a dictionary. So whenever we run latest entry equals and then the
function latest entry will now be a Python dictionary. So then we can assert that there is a
dictionary key called title and a dictionary key called published. We don't have to test the
values because depending on what day the values will be different, but we want to at least test that
the values exist. And we can do that with just kind of a bear assert statement.
So we run the test, the test fails. We write the code that actually gets the latest information
returns a dictionary. Then we run python-v again. We can see now we have three passing tests.
So we'll write one more function to do some testing. Let's say in our actual script,
we verify that we can get the information from the HPR feed. So let's kind of write a final
test that includes looking for all the information that we actually want to print out. So again,
we'll assume that the HPR info script has a function called getentry data.
And that function called getentry data, we can pass it the information that we got when we pull
the HPR feed. So then what we'll do is we'll say entry data equals, we'll write a test in our
test script, entry data equals, and then we'll call the entry data function and pass it the latest
entry data. And again, we're expecting a dictionary back that contains, well it contains what
we want to test for. So we want to test that there's a title, a host, a published date, and a file.
And remember the file is going to be like the path to the archive.org download.
And then as a reminder, you know, all the code, if you want to see the code about how this
actually works, I'll have a few code snippets in the show notes, but full Python scripts as well
as all the tests, all the links to that in my gala project. One little bit of code I will talk
about real quick, is at the bottom of the HPR info script, HPR underscore info script.
There's a section that starts with if underscore name equals underscore main. And that's real
common in Python to have something like that at the bottom of the script. And the reason you do
that is you want to differentiate between when you import the script and when you run the script.
So what I mean by that is when you import a script from, you know, like from your test file and
your importing HPR underscore info, if there's something like print statements or something like
that, those things will probably execute just from importing. So what you want to do is you want
to separate what you want to happen when you call the script directly versus when you just import it
from something else. So it's a little bit of magic. There's reasons, you know,
behind all this, which I understand, but I'm not necessarily going to get into here. But
you know, the way to do that, the way to separate the code that you want to execute when you call
the script, is you put it underneath this if name equals main function. So you'll see that in there.
If you look at the code, well, it'll be in the show notes, or if you look at the code on get lab.
But the reason it's like that is, you know, that's, this is the bit that calls when you actually
execute the script. And what it's going to do, it's going to go through and run code that was in
the functions that we've been testing with TDD. So a lot of times that'll happen with TDD. You'll
write a whole bunch of functions you want to test. And then finally at the end, the last bit of
code you write is tying all these functions you've tested, tying all that together to get the
output that you want it. Okay, that's it. It's all I got. Sort of in summary, you know, test TDD,
test driven development. It's a programming method where you write tests prior to writing the code.
You know, primarily because I like it because it makes me write smaller, easier to understand,
more modular code. I'll have links in the show notes. I don't remember to add those. They're
not in here. They're not in my notes yet. So as long as I can remember to add them, I'll have
links in the show notes. And then just sort of as an exercise, if this is something you're interested in,
you can just sort of part two do this. If you want to go do some homework, you can take the script,
take the test. And then see if you can figure out how to write a test to verify that whenever
the script returns a date, that it's a possible date, that it's a date that makes sense. You can
test that it's actually a weekday. You know, HBR only comes out Monday through Friday, so you can test.
It wouldn't be hard if you know a little bit of Python to write a test to verify that the date
that's being returned is actually a weekday. Or you could test, maybe you could figure out how to
pull in the correspondence page from HBR, do a little bit of web parsing, and then you can verify
that the script that we wrote when it returns a host, that that host is can verify that it's
on the correspondence page. There's all kinds of other things you can do. Again, this was just an
example. I made up, I thought it would be a good way to kind of demo test driven development.
That's it, that's all I got. I'll see you guys next time.
You have been listening to Hacker Public Radio at Hacker Public Radio does work. Today's show was
contributed by a HBR listener like yourself. If you ever thought of recording broadcast,
you click on our contribute link to find out how easy it really is. Hosting for HBR has been
kindly provided by an onsthost.com, the Internet Archive and our Sync.net. On the Satellite
Stated, today's show is released under Creative Commons, Attribution 4.0 International License.