Do you write tests for your code? You probably should.
And most of the time, pytest is the industry standard these days.
But pytest can be much more than what you just get from installing it as a tool.
There are many amazing plugins that improve pytest in many aspects.
That's why I've invited Brian Okken to the show to tell us about his favorites.
Listen in and your Python testing will be faster, stronger, and more beautiful.
This is Talk Python to Me, episode 267, recorded June 4th, 2020.
Welcome to Talk Python to Me, a weekly podcast on Python, the language, the libraries, the ecosystem, and the personalities.
This is your host, Michael Kennedy. Follow me on Twitter where I'm @mkennedy.
Keep up with the show and listen to past episodes at talkpython.fm.
And follow the show on Twitter via at Talk Python.
This episode is brought to you by Linode and Sentry.
Please check out what they're offering during their segments.
It really helps support the show.
Brian, welcome back to Talk Python to Me.
Thanks. It's fun to be back.
Yeah, it's good to have you back.
You've been on a lot of episodes.
You've been on five.
2017 Python Year in Review, 2018 Python Year in Review, the Python Testing Column is a Thing,
30 Amazing Python Projects, which is one of the most popular episodes, actually.
And the book author panel discussion.
So happy to have one more on the list to have you here.
Yeah, it's nice.
I love your show.
Listen to it all the time.
Thanks.
Yeah, and it's good to catch up with you.
It's been a while.
Yeah.
Well, we, I mean, we talk to each other weekly.
That's right.
Of course.
Yeah.
So those of you listening who don't know about Python Bytes, that's our other podcast that
Brian and I co-host.
We each have separate podcasts, right?
Talk Python and I do alone.
You do Test and Code, which is really good.
Yes.
Where do people find Test and Code?
At testandcode.com.
Perfect.
But we also do Python Bytes, which is like a newsletter for Python with analysis and audio
form.
It's a lot of fun.
Yeah, it is.
People should check that out as well.
So I want to have you tell your story because you probably told it four times out of five there
anyway.
So let's just sort of check in and see what you've been up to in the last year or so.
It's been actually pretty exciting.
I think I've told the story before, but I work at Roden Schwartz.
So I work at a test and measurement company.
I'm an embedded software developer and a team lead and a lead engineer.
But I've been focusing for the last 10 to 15.
Half of my career has been on communication testing.
Most of it's been cellular stuff and we're switching over the last year or so.
I've been focusing mostly on Wi-Fi testing.
So that's been a lot of fun.
Okay, nice.
Like Wi-Fi 6, that kind of stuff?
Yes.
One of the fun things lately is some of the work on 802.11x, which is just starting to roll
out around the world in different places.
Yeah, that's cool.
I'm actually very excited about that.
Yeah.
It's neat.
Also, one of the reasons why I kind of focus on testing a lot is I am a proponent of developing
software with testing hand in hand so that you develop tests and code at the same time.
Yeah.
It's always very error prone and unlikely to succeed to say, now that you've written the
code, let's go back and add all the tests to it.
Yeah, definitely.
But people don't learn how to write tests when they're in.
I mean, even college classes hardly ever talk about how to write good tests.
Yeah, there's definitely that sort of splintering there.
Like on one hand, the stuff you're building in college, it's probably not going to be long
lived, right?
It's an assignment or a short project.
You just want to get it done because you also got that English paper and you didn't really
even want to take English.
But now you're in there and you got to do it.
So let's just get it done.
And it's a very different thing to think a team of people have to live with this for a
period of time.
Yeah, definitely.
And with a more and more reliant on, it's a little bit easier of a thing for me to try
to tell people the importance because they're used to working.
A lot of people are used to working with open source projects now and you would never pull
an open source project off the shelf and use it if it had zero tests around it.
Yeah.
And a lot of times you've got to have tests to accompany your contributions back if you're
doing a PR, right?
Yeah.
Yeah, definitely.
It's getting more and more attention.
And I think that's a good thing.
What's the work from home story for you these days?
Do you got to go to the office?
I mean, the world scrambled for everyone, but the only part of my world that hasn't changed
is my work because I've already been fully distributed and whatnot, I guess, other than
conferences.
But how about you?
Yeah.
So it was a hard shift.
I think it was early March, was it?
Really early March.
There was a day where we just got told, grab your stuff and go home.
And we're working from home from now on for a while, at least.
And we had just moved into a beautiful office in July.
So it's...
It is really nice.
Like, it's a place you would want to go to because it's got cool decor and whatnot.
Yeah.
And these giant training rooms and stuff.
It's a good building.
So working from home, the entire...
I had just hired a couple people for the team.
And so training people remotely was...
I thought it was going to be a trick, but it's actually been...
It's gone really smoothly.
Oh, that's good.
And yeah, so we're a remote team.
We are...
So in our county...
So I'm in the county, Washington County that we're in around Portland.
We are supposedly entering phase one.
We're doing this three-stage phase going back to work thing.
We don't know.
We haven't allowed people to go back yet, but hopefully there will be...
There's some people that can more effectively work from the office.
So we're going to try to get those people back as soon as we can, but do it safely.
Do you think you'll have more work from home remote options?
Generally, at the company because of this?
Yeah, I think so.
I think we've...
One of the fears was...
Then I think a lot of companies have seen this.
The fear is that people working from home won't...
They'll be more distracted.
They won't be as productive.
And I don't even know if this is a fair test because everybody's also...
It's not just working from home, but their kids are home also.
Yeah, exactly.
There's also the stress of just what's going on in the world is a stressful situation.
So even though it's not a fair comparison, we're comparing anyway.
And things are going okay.
We're still being productive, just about as productive or more so than we were before in
a lot of cases.
The lack of a commute is really easy.
The ease of discussion.
I mean, you can...
I don't know.
It just is...
I get more time focused, but also I think I'm talking with my team more often now because
we make it a point to talk every day as a team.
Right, right.
Focus type stuff, not just, oh, I passed them in the hall sort of thing.
Yeah, that's cool.
Now, one more thing, I guess while we're catching up on this stuff is you've got these really
beautiful training rooms with nice giant screens.
And one of the things that we were doing together is the Python Portland West meetup, which kind
of got polished from all this as well, right?
Yeah, and that's a big bummer because I think it was really serving a community in the west
side of Portland that didn't have a meetup.
And I would really like to...
I have no idea when we're going to get back to being able to do that, but I'd like to be
able to do something.
Yeah, I don't even know when I can go to a restaurant.
So, you know, things are all up in the air.
The world is crazy.
Yeah, definitely.
Yeah.
All right, cool.
Well, good to catch up.
Now, let's talk some pie tests.
I'd like to do just a little bit of high-level stuff to just like set the stage, and then
we're going to dive into the plugins.
So, pytest is an external separate way to write and test Python code.
Just not, say, part of Python like UnitTest.
So, maybe let's just do like a quick survey of the modern testing tools that people might
potentially use, and then like how we'd write tests in pytest for those who maybe have only
done UnitTest type testing, or they're like, testing, maybe I should do that.
Yeah, sure.
Sure.
Well, actually, you had a few on the list that I deleted, but...
Because they're no longer modern, right?
Well, I would say not.
There still is UnitTest, and UnitTest is being supported, and I do think, and it's part of
the Python distribution.
That's the one winning point, I think, right?
It's like, I don't have to have a requirements.txt or pip install anything, potentially, and I
can still write tests.
Yeah.
One of the main reasons why it's there is to test Python and test the standard library.
And I think that that's a good reason for it.
There's a bunch of people that have built on tools around it, and I think that's fine, but
it's just not my thing.
One of the things, while we're talking about other testing app things, is it's a good thing
to note that Nose is still available, but I don't recommend anybody use Nose or Nose2 or
any of its variants, because, I don't know, Nose is not being supported at all anymore.
And Nose2 has very little traction, and I don't know if it's, I don't currently know
if it's active.
So, if you're currently working on Nose, sorry about the disparaging remark, but maybe correct
me if I'm wrong.
Yeah, yeah.
Well, I mean, the thing is, you've got all these choices, right?
Like, if it's pytest or some of these other things like Nose or something, it's like, well,
okay.
Which one are you going to pick, right?
First got into it, I really, I was looking for the easiest.
And I thought that maybe the easiest and the most powerful would be two different things,
but it turns out that pytest is both the easiest and the most powerful, which is nice.
Nice.
There's some other ones, though, that you might consider.
Yeah.
Well, in conjunction with pytest and other testing things, there's a lot of other tools that people
use.
Tox is used, it is not just a testing tool, but one of the neat things about it is you can
do a test matrix or running different Python environments.
It creates a, it tests a lot of your application.
It's pretty, almost an episode in itself.
Right.
You can test on like various versions, like Python 3.5, 3.6, 3.7, and stuff with that, right?
Yeah.
And typically, if you're running, like running pytest, pytest doesn't automatically build your
application for you, but Tox, part of its process is creating the wheel of your, like if you're
doing a package, it'll create the package for you and then install it.
And it does the whole round trip thing.
So that's cool.
Nice.
Okay, cool.
A lot of people are moving to, so continuous integration is definitely a thing that's important
everywhere.
And a couple years ago, it was probably Jenkins or Travis that people were using, but now
I think more, a lot of people are moving to GitHub Actions because they're just right there
with your code.
So why not?
Yeah, that's super easy.
And it totally solves the problem that is, I think, one of the really big challenges of
testing in teams is you get different levels of buy-in from different participants in the
team.
And some people are very, they just are reluctant to just run the test before they'll do a check-in.
Yeah.
They'll break the test, they'll do a check-in, and they don't even know they broke it, but
they don't care that much.
I mean, people care to differ in degrees, but it's like, well, they're kind of a nuisance,
but I guess if you're going to make me write tests, I will.
Right.
And so the continuous integration is like, everyone gets checked before we accept your
stuff, right?
Well, right.
So hooking it up within a GitHub Action, you could do this before, but it's really easy with
these, is to just say, if you'd like, for instance, a merge request doesn't even go,
doesn't even go very far if the test fails.
So yeah.
Listing coverage.py, because I'm, if you care about coverage, that's how you do that in Python.
I don't do a lot of web testing, but I wanted to point out that Selenium and a wrapper around
Selenium called Splinter are very commonly used.
And then these are all packaged very well within a plugin called pytest Splinter so that you
can easily control web applications.
Nice.
I hadn't heard of that one.
I've heard of Selenium, but not Splinter.
Yeah.
A property-based testing is gaining a lot more traction in conjunction with functionality testing.
And the solution within Python is a hypothesis for that.
Nice.
So everything you've listed here is pytest Plus, not instead of, right?
Well, sure.
It's pytest Plus these other things.
However, they, I mean, none of them are pytest only.
So you can use unit test with all of these things as well.
Yeah.
Or yeah, testing framework plus, right?
They're not necessarily alternatives.
Yeah.
Right.
All right.
Cool.
So those are definitely neat things to look into.
They're separate projects.
This portion of Talk Python to Me is brought to you by Linode.
Whether you're working on a personal project or managing your enterprise's infrastructure,
Linode has the pricing, support, and scale that you need to take your project to the next level.
With 11 data centers worldwide, including their newest data center in Sydney, Australia,
enterprise-grade hardware, S3-compatible storage, and the next-generation network,
Linode delivers the performance that you expect at a price that you don't.
Get started on Linode today with a $20 credit, and you get access to native SSD storage,
a 40-gigabit network, industry-leading processors, their revamped cloud manager,
cloud.linode.com, root access to your server, along with their newest API, and a Python CLI.
Just visit talkpython.fm/Linode when creating a new Linode account,
and you'll automatically get $20 credit for your next project.
Oh, and one last thing.
They're hiring.
Go to linode.com slash careers to find out more.
Let them know that we sent you.
Now, like I said, just for people who maybe haven't written a test in pytest,
like, what's the really quick flow?
Like, why is it so simple?
pytest has a really great discovery mechanism, but a function that just starts with,
like, if you have a test file that starts with test underscore,
there's some naming conventions.
So the easiest thing is to have a test file that has test underscore in it,
and then start your functions, test functions with test underscore,
and then it'll all just get run.
So pytest will find all of the files that start with test underscore and run all of the functions
within them that start with test underscore, and then that's it, really.
And so how does a test pass or fail?
It fails if an exception is raised, and the easiest way to raise an exception is to,
if you're intentionally checking something, is to use assert.
So you, like, assert A equals B or something, and if the assertion fails, your test fails.
It's that easy.
Yeah, so you don't have to have decorators or derive from certain classes or anything like that.
It's just the name involves test underscore, and you assert stuff.
That's pretty good.
Yeah, you don't even have to import pytest into your test files.
They can be just functions.
Yeah, that's right.
So unless you're using some of the unique features that, like, extend pytest,
like you talked about the way a test fails if there's an exception.
Well, if you're testing for error handling,
sometimes you want to trigger an exception and verify it has happened.
So in that case, you'd have to include some pytest stuff to do, like,
the width raises sort of stuff on it.
But in general, for, like, the straight-ahead test,
you don't even need to import pytest.
Which is kind of weird.
That freaked me out a little bit at first.
I'm like, why am I not interacting with pytest?
This is so weird at a code level.
No, it's beautiful.
It's one of the things I like is that it's just easy to start.
Absolutely.
Now, one other thing I want to cover before we dig into the list of plugins
that we're going to cover is there's some non-obvious other ways to extend pytest, right?
Like, it has this concept of fixtures that allow you to create and initialize stuff,
and then automatically pytest has a way to, like, pass it along to your tests and whatnot.
You'll see some of these plugins actually use fixtures, like some stuff about modifying time and whatnot that we'll talk about.
What's the deal with those?
Well, so the unit test model, and the unit test is similar to a lot of the X unit type, like J unit and PHP unit and stuff,
have a similar model where you just, things are just named also and the tests get run.
But there's often times where you need stuff to happen before your test gets run,
like setting up a resource or generating data or something like that.
And there's, so there's setup and teardown functions that you can, that are associated with these other test frameworks.
pytest actually also supports those sorts of setup and teardown functions.
If you want to use them, they are supported.
But it's really not recommended because fixtures are so awesome.
So a fixture is a way to combine, like, to write a function that is handling a resource or handling some data
and be able to do the setup and teardown within one function and, if necessary.
And then also just be able to scope those.
And you can, you can have them have the resource or data shared between one test or many tests or even across the entire project.
And you can control, you know, like if you're initializing a database or connecting to a web resource,
you might not want to do that for every test.
You can do it for one, once per session and then, and then do things like rollbacks and stuff per test.
And that granularity of being able to shift your, the granularity of your setup and teardown is super powerful
and really helps makes pytest shine.
Yeah.
And the way that you write it is super cool as well, right?
Just have a test function that just takes a parameter.
The parameter is named the same as the fixture and pytest just says, okay, I really call this function and pass it over.
It could do really cool things.
Like you could pass off your database data access layer and it could start a transaction before, hand it to you,
and then roll back the transaction after the test is over.
Right.
And you don't have to worry about it.
It could just take care of that for you.
Yeah.
Yep.
And the fixtures are really what brought me to pytest.
Some of the, there's some massively cool things you can do with that.
Like one of the things that people don't think about is if you've got a system under test that has error logs somewhere,
one of the things you can do within a fixture is check your error logs after the test runs to make sure there's no fatal errors that got saved somewhere.
Yeah.
Very cool.
Love it.
Okay.
So that's one way.
The other one is this plugins in general, right?
Like there's ways to extend pytest with plugins as a concept.
The pytest has a whole set of hook functions as well.
There's, there's a lot of things you can do.
You can, you can write fixtures and package those fixtures for other people to use.
So some plugins are just packaged fixtures.
Other things you can do with hook functions.
So with, I actually was intimidated when I first was reading about hook functions, but they're just, there's just a way for pytest to allow different parts of the way pytest runs to be hooked into.
So you can, you know, alter a few things if you need to, like, like some of the test ordering ones.
Once all the tests are collected, you can hook into that section and reorder them if you need to, or, or filter them.
Choose which ones execute, right?
Yeah.
There's a whole bunch of ways you can hook into it and it's fairly complex, but a lot of people have come up with some really clever things and plugins allow you to allow you to do that.
And I mean, not just third party plugins that you can pull off of PyPI, but you can also just, if you want to share some code that you have that works with your tests amongst different projects, you can package your own plugins to do that.
Yeah.
Oh, that's cool.
You could even have them for like your company, right?
Like we always do this in RCI and whatnot.
You can just grab a plugin and do stuff.
Yeah.
Like I've got plugins that I've written that, that just are particular to one particular test piece of test equipment.
So to control this piece of equipment, you can use this plugin and it helps you with some of the common things.
Oh, that's cool.
Makes it a little easier for new people.
Yeah.
Lots easier.
Nice.
All right.
I think it's time we go down the list.
We've set the stage.
We know what fixtures are.
We know what plugins are, at least in general.
Let's put some sugar on pytest to make it sweet.
Yeah.
So we're going to run through a whole bunch of really cool pytest plugins, right?
Yeah, absolutely.
All right.
What's this first one here?
So sugar is a fun one, actually.
I ran into this right away with looking at pytest.
So the default output of pytest is you, when you run it, you get a dot shows up for every, for every test that gets run.
And it does list the files, but a little dot shows up.
And maybe that's not enough for you.
So pytest sugar shows you, like, green check marks instead.
So, and then, you know, instead of, like, Fs for failure, I think there's, like, red Xs or something that show up.
So it alters the output of pytest so that it looks a little nicer.
Yeah, it also looks like it might be suppressing the module name, the folder names, and only, like, highlighting the actual file names.
So it does, like, gray out a little part of the UI.
So, like, the actual test file being run stands out.
And there's a vertical progress bar going along that runs as well.
That's pretty sweet.
Yeah, that's pretty cool.
And that was especially really helpful before pytest added the percentage done.
So now, for each file, pytest lists the percent done now by default.
But it didn't always have that, and pytest sugar had that.
It's pretty cool.
Yeah, it's cool.
And there's a nice little animated GIF, as all things should have, on there that I'll link to in the show notes so people can check it out and see it going.
So, yeah, pytest sugar.
And this is cool because all you've got to do is install this, and it doesn't require effort, right?
And, like, oh, and now I can do this thing in code.
It's just, like, I install this, and it looks better.
Yeah.
How do you install plugins?
Just do you pip install them?
Like, do I need to register it with pytest, or is it sufficient to just pip install it?
Just pip install it.
It's about the design of the plugin as well.
So some plugins, like Sugar, you just install it, and it starts working.
You don't have to do anything.
All right.
But some of them intentionally don't start right away.
So some plugins, they are installed, but you have to turn on the functionality with a flag or something like that.
Got you.
Okay.
Cool.
All right.
What's the next one?
Number two.
So this one's definitely something, pytest cov, dash cov, it's a way to run coverage with pytest together.
So, I mean, there's really two ways to run coverage on pytest tests.
Coverage doesn't require pytest, right?
So you can use any test framework.
So you can run pytest from coverage, or you can run coverage from pytest.
It's kind of a choice.
But I usually use pytest cov because it's just really well supported.
It does some really cool things.
One of the things that it does really nice is, we'll talk about xDisk later, but xDisk allows
parallel runs.
And pytest cov cleanly collects all of the different parallel runs and pulls the report, coverage
report together for you.
Oh, that's cool.
Which is really nice.
Yeah, it has xDisk support, which we'll talk about what that means.
But that's a pretty high-end piece of kit there to go grab a parallel executing stuff and bring
it all together.
Yeah, and there's also, it's really good about catching the coverage from right from the beginning.
So you've got like some startup code that happens, like your fixtures and stuff that you've set
up that run before your tests, making sure that those have coverage turned on as soon as
possible so that you don't have startup code that doesn't get run and coverage.
That's one of the issues with hooking up coverage often.
But pytest cov handles that really cleanly.
Yeah, awesome.
It also has sub-process support, so you can fork things into a sub-process and it'll get
covered automatically, which you might think, okay, who's going to do that?
And like, do they really care about tracking the coverage of it?
But, you know, multiprocessing, right?
They're doing parallelism.
Yeah, definitely.
Yeah, that's good as well.
Very nice.
The other nice thing about it is just, so if you're, it makes it easy to have a text output.
So normally when you run coverage outside of, like if you run pytest from coverage, once
you're finished, you have to then tell coverage to give you the reports.
You have to run coverage report to get your coverage report.
But pytest cov just prints that at the end.
So you get that automatically.
Don't have to run it again.
Cool.
Very nice.
Would you say it's low stress?
It is low stress, yes.
Unless the stress is trying to get 100% coverage.
Well, that's true.
Actually, what are your thoughts on, I'll share my thoughts with you as well, but, you know,
a lot of people feel like they're not testing well if they don't have 100% coverage or they
don't have any coverage.
So they don't even know like how much of their code is being run by tests.
Like what are your thoughts there?
I am a strong proponent for open source projects to have 100% coverage because it eases new
people, new developers into the project.
When they add code, it's easy for them to find the code that they added that isn't being covered
yet.
It doesn't necessarily mean that your tests are good.
It just means that their code's covered.
For open source stuff, it's good.
And then if you take that argument, then it's good for internal projects as well because it's
easier to run stuff.
However, I'm not a zealot about it.
I mean, if you're like jumping into a legacy project and adding software tests to a project
and you're testing the new stuff and the things that you change, you're never going to hit
100% coverage of like the rest of the legacy code.
And, you know.
Yeah, I agree with that.
I feel like a lot of people get hung up on like the last mile for applications, like for
open source projects where it's like a library or something.
Sure.
It should totally all be there.
But there's like in certain apps, there's just little edge cases.
Like if I'm running on Windows, I got to do this other thing, but I'm only testing this
on macOS or on Linux.
Right.
So like how much should I stress about trying to like get that little edge piece of code to
run or like there's this.
This one utility that only I run and a cron job to do this thing.
I don't know.
There's just all these little edge cases that can be like a whole lot of work to get to.
But I feel like, you know, most of the time, you know, you should probably not stress too
much about it.
Yeah.
So all those edge cases are the reasons why I think you should test those.
Because.
Okay.
So we have ways to combine coverage reports.
So you can use something like GitHub Actions or Travis or something to run your, run your
code on multiple platforms and combine the coverage from the test runs from multiple platforms.
So why not run them on multiple platforms?
If that, if you have platform specific code, if you have a platform specific code, I think
there's a reason is because some of your customers use it.
And if it's different than what the developers use, I think you should test that code.
Yeah, that's probably true.
That's a good point.
That's the only place it gets run before it gets deployed.
All right.
Well, my transition to the stress one, we got kind of sidetracked.
But this next one is all about stress.
Yeah.
So I think we should actually just cover a couple of them.
So the next two.
Yeah.
They're kind of a good pair.
Yeah.
And pytest repeat.
So pytest stress is a nice thing.
So let's say you've got some code that you just run it like overnight.
I know that I'm going to leave it like a mid.
I want to, I know everybody's going to be out of the building by midnight.
And then I want to just beat on the code and run it as many times as I can for eight hours.
So pytest stress allows you to be able to run a set of time to say, hey, run this for eight hours or run it for a half an hour, run it for a certain time period.
And that's really cool if that's where you're thinking.
And then repeat.
pytest repeat allows you to run your test suite or test functions or whatever a certain number of times.
So I want to set it up for a thousand times.
I bring these up together because I found pytest repeat first when I needed to.
I had some tests that, a test that was failing once in a while and I just wanted to run it all night long.
And so I just set it for a large number like 2000.
I don't know.
Like I just guessed.
But really what I wanted it to do was run all night.
And so pytest stress would have been better for that case.
Oh yeah, that's a cool one.
You know where I would see these as being useful?
Sometimes I'm trying to do profiling, like CPU profiling to figure out or maybe even memory profiling.
And the startup of getting the pytest or whatever it is up and running and all the stuff in place and then running a little bit of code and then tearing it all down.
It's like gets dwarfed.
You know, the actual bit you're trying to understand gets dwarfed by all that startup.
But here you could just let it run for 10 minutes and then it'll be really focused on what it was slow at.
Then that's where actually with profiling, I think that would be a good place to use the repeat.
So you could say do a nice round number like 100 times or a thousand times because it's easy to divide by that.
Yeah, yeah, that's a good point.
Exactly.
Nice.
What's this next one?
InstaFail.
So if you had a whole bunch of like print statements and whatever in your code, it doesn't get shown normally with pytest.
So pytest will capture the output by default.
I mean, you can turn it off.
But by default, it captures the output and any errors and failures and stuff.
Those get captured also, like tracebacks and stuff.
And then afterwards, so after the test is done, you get your report and then you get a lot of this output that you can help debug your test failures with.
With long running tests, sometimes it'd be really nice if you really could see those errors while it's happening.
So you can start looking at the code and start debugging right away.
And that's where InstaFail will report your failures and errors while the test run is happening, even with output being captured.
Nice.
Is there a way with plugins where if I've installed InstaFail, but I only want to see it some of the time to like encode, say, you know, don't run InstaFail right now.
But sometimes when I want it, let it run without pip uninstalling it.
I'm not sure, actually.
That would be sweet.
Yeah.
I don't know.
It could be up to them individually, but it would be nice if maybe a command line or something.
I don't know.
Some way to say, actually, I want this other one turned on now, but not always.
Well, I'm just looking at it.
So it looks like even if it has it installed, it doesn't.
This is one of those that it doesn't run automatically.
You have to pass in the flag.
I see.
Okay.
Cool, cool.
To turn it on.
Nice.
Speaking of passing flags and whatnot, pytest metadata is the next one.
Number six.
Yeah.
This is a kind of an obscure one.
And this is often used with pytest HTML, which actually we're not covering.
Maybe we should.
But pytest InstaFail, or not InstaFail.
Metadata.
Metadata allows you to either through, it gives you a couple of things.
It has a command line flag where you can pass in extra information to go into your test report.
And then also you can within, so like for instance, if you're running against a particular set of servers,
you could have the server name getting listed in the report.
The other thing is maybe the data that you really want to log, the extra metadata about a test run, is generated or like in real time is developed or gotten from within a fixture or something.
So a fixture or a test can set this extra metadata and it gets output with your test data.
Oh, cool.
Like maybe what GitHub branch you were running on or what environment like staging or production testing or whatever.
Yeah.
Yeah, cool.
Or maybe adding, you know, what operating system.
I mean, your operating system's already being logged.
But if there's other information like, yeah, what branch, what version, what some of the extra specifics.
Yeah.
That's cool.
Yeah.
That sounds useful.
Like if you're saving the report and you're going to look at it later, like maybe continuous integration or something like that.
Yeah.
So like for instance, when I'm testing against electronic test equipment, we add the instrument that we're testing against.
So that's just part of the log.
This portion of Talk Python to Me is brought to you by Sentry.
How would you like to remove a little stress from your life?
Do you worry that users may be having difficulties or are encountering errors with your app right now?
Would you even know it until they send that support email?
How much better would it be to have the error details immediately sent to you, including the call stack and values of local variables, as well as the active user stored in the report?
With Sentry, this is not only possible, it's simple and free.
In fact, we use Sentry on all the Talk Python web properties.
We've actually fixed a bug triggered by our user and had the upgrade ready to roll out as we got the support email.
That was a great email to write back.
We saw your error and have already rolled out the fix.
Imagine their surprise.
Surprise and delight your users today.
Create your free account at talkpython.fm/sentry and track up to 5,000 errors a month across multiple projects for free.
And if you use the code talkpython, all one word, it's good for two free months of Sentry's team plan, which will give you up to 20 times as many monthly events and some other features.
So create that free account today.
Yeah, I don't want to just be random.
Not just random.
Yeah.
But sometimes you do.
So one of the things that pytest will actually, I think I've intentionally forgotten the test order.
I think it's alphabetical or just it's not alphabetical.
It's like the order that the tests are in in the file.
That's how the default order that things get run in.
But you really don't want your test to be order dependent.
So you want to be able to run any test in any order.
And sometimes a good way to test that is with the pytest Randomly plugin.
So it does a couple of things.
One of the things you can do is it can reorder your tests so that they're running in a random order.
But also you might be using random as a seed for some randomized information.
Like say, like Faker, for instance, and other fake data generators use random seeds.
So pytest Randomly can help you randomize that stuff so that it's more random.
Yeah, that's cool.
It says that if Faker, which is a really cool library, if Faker is installed, it'll automatically update it.
So that Faker is different this time than another time.
Same thing for NumPy.
Yeah, this is really cool.
Anytime you have your test running reliably in the same order, you could unintentionally pick up some form of dependency on order.
Like if you call this test, it like initializes the database connection string.
And then you can call this other thing and it'll work.
But if you call it in the other order, it would crash.
I mean, maybe that's a bad example because you really want to avoid that dependency.
But you know what I mean?
Like it could set something where the next thing depends on it being set that way.
And if you randomly order it, then you're going to discover those.
Yeah, especially with your scoping your fixtures to try to speed up test time, you might inadvertently have dependencies like system dependencies.
For instance, you get the system in a particular state in one test and then you're running another test.
One of the problems often is you got a test that runs fine when you're running it from your editor.
And then you go into on the CI system where it's running everything.
It fails.
And you can consistently fail it with the entire suite, but not by itself.
Those are just a pain in the rear to find out where the problem really is.
And I mean, randomly can help you.
I'm not sure how well it can help you debug that problem, but it can help find dependency.
Yeah, at least it won't leave it covered up, hidden.
Yeah.
Well, you already mentioned exodist earlier when we talked about pytestCov.
So what's this exodist?
Well, exodist is super powerful.
It's a little bit of a grab bag of a few features.
One of the things that it does, and people usually grab it for this, is to run tests in parallel.
So you can tell it how many CPUs to run on and it'll just run a whole bunch of tests in parallel.
And that's pretty cool.
It can speed up tests.
It does have a little bit of startup time because it's communicating with the different, you know,
it's doing multi-process communications, a little bit of startup time.
So if you have independent tests that don't share a resource, this can be really cool.
The other thing that you can also just offload it onto different processes or different computers,
you can have it be running on different machines as well.
So that's pretty cool.
That's cool.
That's really cool.
Yeah, that's very fascinating.
And then I don't know why this is bundled into it, but this is a really cool feature of pytest
exodist is the loop on fail feature.
So you can pass it loop on fail and it'll run your tests repeatedly in a sub process.
And then you get to see what the failures are.
But if it detects you've changed your project at all, it'll rerun the test, but it just reruns the failing tests.
So it just keeps rerunning all of your failures while you're trying to fix it.
And then once all of them are, when everything's running and fixed, it'll rerun everything.
So when they all pass, it'll rerun the whole suite.
Yeah, super cool.
So it's a little bit like in PyCharm where you can say, run the test when anything changes,
but this only does it for the failure.
So you're like, you got to, you write a failing test or you have a failing test you're trying to fix and you can just work on it.
And it only focuses on that thing.
Yeah.
I mean, it kind of is all the passing ones too, because if your suite is passing, it just keeps rerunning it every time it sees a change.
I see.
Okay.
Yeah.
Cool.
All right.
Well, one way your code can fail is it doesn't execute properly, makes a mistake.
The other one is it could just not be formatted the way you like or break some of the idioms that you're supposed to write.
Yeah.
There's a whole bunch of extra plugins that are like this, but they're style guide stuff.
So pytest Flakes is one where it can run Flake 8 and other things against your code as part of the pytest run.
It can test both your source code and your test code if you wanted to.
I actually think this is a pretty cool idea, but there is some controversy as to whether this should be really part of,
your pytest run or it should be part of like, say, do a pre-commit or something.
But I think having it in both places is fine.
If your workflow is mostly people run pytest to make sure all their code's working and then they're ready to check it in.
If you want to make sure you don't, it's just your workflow, whether you like to catch your Flake errors during commit time or during test time.
Yeah.
And I just noticed the one that I grabbed to throw into the list, there was pytest Flakes, I think.
And they say you should use pytest dash Flake 8.
So I'm going to link to that one.
But same idea.
Yeah.
There's also a pytest PEP 8, I think it is.
There's like various different ones for this.
Yeah.
And I got to admit, I'm like a little, I guess, over the top.
I use both pytest Flake 8 and hookup Flake 8 to pre-commit hook.
So just because, I mean, pre-commit is so fast.
Why not?
Yeah, absolutely.
Cool.
Speaking of being fast, you know, your tests sometimes are slow because it's a lot of work to run your tests.
Or they could just be stuck waiting on something.
Yeah, I really like, so pytest Timeout is a plugin that is a fairly big hammer to a problem.
But you've got tests that maybe it loops forever.
You forgot to put a timer on something.
Or it's stuck on a resource.
Or for any reason, it's hung.
And I suggest people use pytest Timeout for any long-running suites all the time.
For really short, fast tests, there is a little bit of overhead.
But for any sort of long-running stuff, the overhead is negligible and you don't see it.
But what it does is it runs your tests in another thread and then is able to kill it.
So it will just put a timer around it and kill the thread if it doesn't come back in time.
Why I call it a big hammer is because if it fails, you don't get your test output.
But it also doesn't hang forever.
And these are especially good for CI systems.
Because you really don't want to come back in the morning and notice that your test suite has been running for 12 hours.
And it's only really supposed to run for 20 minutes.
Yeah, absolutely.
Yeah, if it's unattended or it's really long-running or you're talking to something that who knows how long it's going to take to respond.
Yeah, maybe even have that with instruments that you're testing and whatnot.
Yeah, we definitely use it.
And the nice thing is you can have a global timeout to say, hey, no tests should run longer than this long.
So whatever, 10 minutes.
Whatever is in your system is a reasonable amount of time.
And then you can override that within.
We can put decorators on individual tests to say, well, this test is really fast.
It really should only be this long.
And whatever, you can fine-tune it if you need to.
Nice.
All right, another one.
I think I threw this one on the list is spec.
Yeah, I don't know anything about this.
Yeah, so spec, it's a little bit like sugar.
It allows you to sort of control the output.
So you can group tests by classes or by files.
The failed, passed, and skipped ones are marked and colored.
You can remove like test underscore and underscore stuff from the test.
So it'll like, you might have a name where it's like test user can log in with underscores.
And I think it'll take those out so it looks more like English, like user can log in or something like that.
So it's just a nice little one for customizing.
There's some options you can pass to it and whatnot.
Cool.
Yeah, yeah.
I've heard you talk about pytest Picked before.
Yeah, that's a fun little plugin.
So do you remember what this does?
Yes.
Yeah, so this is the one.
And we weren't totally sure like how smart it was.
We had a bit of a conversation about it.
But this one will run tests that are not checked into GitHub or have changes that are not checked into GitHub.
Oh, that's nice.
Yeah, so it'll run tests related to unstaged files.
And if it sees some that are, you know, there, it'll basically, if you're in a GitHub repo, you can run tests that are modified, but not checked in, not committed.
Yeah, and that's usually often what you want to be doing, right?
Exactly.
What I would really like it to do, and I don't think it does, and people can add a comment at the bottom of the show page if that's changed or still misunderstood.
But I would love it to somehow use coverage to see what are the files that need to be retested.
Like what tests touch, like I've got a non-test file I change.
What tests need to be rerun?
I think it only just reruns the tests that are changed.
I don't think it uses coverage, but I could be wrong about that.
But nonetheless, it's still pretty cool.
Yeah, I mean, all of the pieces are together for somebody to do something like this.
Yeah.
Because coverage has a context feature now, so you can tell it.
And with pytestCov, it automatically sets it up so that you can tell which tests touched which parts of your code.
And the idea seems like great.
One of the issues with that is there's a whole bunch of your code that gets hit by every test.
Yeah.
Because it's like startup code or something like that.
Right, right.
Well, you just don't change the startup code.
You can't edit that part.
Yeah.
No, but still, it is a really cool idea to say like just run the stuff that might have had some influence on.
That's really cool.
Yeah.
So pytestPick doesn't do that, but it has this.
It does a really cool, it's a nice addition to be able to run the tests that you're working on.
Yeah, I could totally see just running this and then using like a pre-commit hook to run everything or just, you know, right before you check in, just run everything.
Or even just check it in and it runs in CI and doesn't get merged if it fails, right?
Like if there's some other gated mechanism further down, then this seems pretty cool.
Yeah, definitely.
Yeah.
So this next one, FreezeGun, is all about time.
And this one I feel like is probably packaged as a fixture.
At least it has a fixture concept.
Definitely as a fixture.
It doesn't run by default, but you have to kind of turn it on when you know it.
Yeah, this one, people know it once they hear what it does.
You don't want this to run by default.
I like to list this one, but just, it's such a great name, FreezeGun.
Oh, yeah.
It's for changing time.
You can easily, there's fixtures around it so that you can easily either freeze time so that you're, anytime you grab the time of day or the date time stuff, it's always going to be the same.
Or you can, you know, fast forward or change the date or do things like that.
So one of the hard things is around testing code that deals with time because you have to know what the answer is going to be.
And it's going to be different every time.
So FreezeGun allows you to test time-related tests really easily.
Plus, it's just such a great name.
It is.
And you have these functions, they can take a freezer object and then basically that, what is that probably behind the scenes patch, like the time functions, date time.now and whatnot.
And then you can also do like freezer, move to some other time.
And then like instantly you are transformed either into the future or the past.
Yeah.
And I think some people might be using mock for that sort of thing in the past, but this is cleaner.
Use this.
Look, if you could say, let's mock out date time.date time.now, or you could use FreezeGun.
Like, which do you want to do?
Come on.
Exactly.
Yeah.
FreezeGun.
All right.
We've got one more that's on your list and then an extra one I threw in at the end.
pytest-check.
Yeah.
I wrote a plugin called pytest-check and solved a problem I had.
So the problem is the normal way to stop or to fail a test is to use assert or raise an exception.
Both of those stop the execution.
I wanted to be able to do lots of things.
Like if I want to test lots of attributes of some object, I want to be able to have a lot of things.
I want to have lots of checks in there.
And I want to see all of the failures, not just the first one.
So pytest-check solves this by allowing multiple failures per test with these little check functions.
But you can also, it also provides a context manager so that you can say within this context, you know, you can use normal asserts, but within a context that will continue after that context.
So a similar solution is available called subtests and with the pytest SubTest plugin.
But I still like pytest-check better because it works with stop on fail and X fail, whereas subtests do not.
Okay.
Yeah, this is really cool.
So you can pass in a check fixture to your test and you can say check greater AB less than or equal to this.
This is not in that.
And then it'll tell you like it was not greater and it's not in there as the error.
It's just something like that, right?
It's a fairly simple thing.
It's a fixture that just collects failure.
It like wraps things right with an assert context manager or a try except block.
And if a failure happens, it just, instead of stopping the test, it records it into a list.
And then after the test is complete, it'll like kind of hack with the pytest guts to make it fail.
Okay.
That's really cool.
I definitely like this.
I'm thinking like if I get just the text printout of the build failed or the CI failed, you know, even, you know, that I just see it.
And then when I'm running it and like PyCharm or something, I'd like to just look at it and go, oh, it failed because if this is true and that's true and this,
like I see, right, you don't have to go and actually debug through it or be, it might be that there's enough information here to actually know what's going on and just fix it.
Yep.
And also just more information is good sometimes dealing with, I mean, I definitely use it a lot with test equipment, with signal processing and stuff.
A signal might be wrong, but why is the signal wrong?
It might be the wrong frequency.
It might be the wrong bandwidth.
It might be, I mean, lots of different things.
And if I'm checking four or five attributes of the signal, I really want all of that information for a failure.
Yeah, I agree.
There might be different aspects that all come together to make it successful.
So report all the aspects.
Yeah.
That's cool.
All right.
I want to throw one more in that's not really part of pytest per se, but absolutely can be used with pytest because, hey, it raises exceptions.
And that's called fluent check.
So this one allows you to use a, well, a fluent API, you know, where you say operation one dot operation two dot operation three to have a more English language thing.
And to me, it feels a little bit like your check as well, but it's not a pytest plugin or fixture.
So it has a couple of APIs.
I like the is API.
So you can say like is in dot not none dot float dot between zero and one, and it'll actually check all those things and report like nice messages.
Like if it's not a float, it would say, you know, whatever it is, here's its value is not a float and you expected it to be right.
So a little more readable.
Some people like it.
Some people just want to assert stuff and either one's fine.
But if you like the style, this is a pretty cool library.
It's not mine, but I did do some PRs.
I did basically create the is API for it.
Cool.
Does it have not a hot dog?
It should also have is a teapot or something like that from the for web testing, you know, the four for 18.
Yeah, we should throw some of those in there.
Like, why not?
We do it.
Anyway, those are kind of fun for just like inside your test expressing what you're testing a little bit better.
I think check is really cool as well.
And it's a bit similar.
Yeah, but this one doesn't stop.
It just throws the first one.
All right.
Well, that's a great, a great list.
You know, maybe just really quick, we could check in.
How's your book doing?
You wrote a book about some of the stuff.
Yeah.
So I wrote Python testing with pytest.
That was gosh, it was it's been a couple of years now that it's been out and it's still going going strong.
The of course, the big chunk of sales right after the book was released and quite a few during beta too.
And that was neat.
But it's still selling really well.
And I'm really happy with it.
And it's still valid, even though it's it's a couple of years old now.
And I wrote it in conjunction with talking with a lot of the pytest core maintainers to make sure I wasn't putting anything in there that would be deprecated soon.
Yeah.
So it's still valid.
It's good.
Awesome.
Yeah.
People can take that up.
They want to read, you know, dive into this much more.
And then also you did an episode that also talked about pytest plugins over on testing code.
Yeah.
It was episode 104 with Anthony Sotil.
The episode that you and I just did, we kind of picked our own, some of our favorites, some of the things that we think people should know about.
What we did with episode 104, we took download counts and took the top some of the top 28 downloads.
I see.
Popular by usage, not by curation.
Yeah.
Yep.
Exactly.
Awesome.
All right.
Well, this is really fun, Brian.
But before we get out of here, two final questions as per usual.
If you're going to write some Python code, what editor do you use?
PyCharm.
All right.
Right on.
It's got some sweet built-in test runners.
Yeah.
It's really clean with testing.
Yep.
And then notable PyPI package.
I mean, I guess many of these are.
Anything in particular comes to mind you want to throw out there?
It's something different.
I'm kind of a huge fan of Flit for packaging.
So that's the easiest way to package right now, I think.
All right.
As opposed to some of the other alternatives like pip and PMP and setup tools and all those
things, right?
Yeah.
Sweet.
All right.
Yeah.
What is that?
There's poetry and...
Yeah.
Poetry as well.
That's right.
All right.
Well, final call to action.
People are excited about pytest and pytest plugins.
What should they do?
They should buy my book, actually.
So one of the things I made sure to do is to tell people how to create their own plugins
within the book.
So I think it's a really good introduction to that.
Also, I guess, final call to action, go subscribe to Testing Code and podcast also and test your
code.
Go out and test something.
Do you guys talk about pytests over there sometimes?
Sometimes.
Yeah.
A lot of times we do.
Yeah.
That's great.
Awesome.
Cool.
Well, thanks for being on the show.
Nice to have you back as always.
Yeah.
Thank you.
You bet.
Bye.
This has been another episode of Talk Python to Me.
Our guest on this episode was Brian Okken, and it's been brought to you by Linode and Sentry.
Start your next Python project on Linode's state-of-the-art cloud service.
Just visit talkpython.fm/Linode, L-I-N-O-D-E.
You'll automatically get a $20 credit when you create a new account.
Take some stress out of your life.
Get notified immediately about errors in your web applications with Sentry.
Just visit talkpython.fm/sentry and get started for free.
Want to level up your Python?
If you're just getting started, try my Python Jumpstart by Building 10 Apps course.
Or if you're looking for something more advanced, check out our new async course that digs into
all the different types of async programming you can do in Python.
And of course, if you're interested in more than one of these, be sure to check out our Everything Bundle.
It's like a subscription that never expires.
Be sure to subscribe to the show.
Open your favorite podcatcher and search for Python.
We should be right at the top.
You can also find the iTunes feed at /itunes, the Google Play feed at /play,
and the direct RSS feed at /rss on talkpython.fm.
This is your host, Michael Kennedy.
Thanks so much for listening.
I really appreciate it.
Now get out there and write some Python code.
I'll see you next time.