Building Data-Driven Web Apps with Pyramid and SQLAlchemy Transcripts
Chapter: Testing web apps
Lecture: Getting started with tests
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
And see we have a new project pypi_testing. Again, this just sort of a save point. Let's open that up. Now when we created this, we used Cookiecutter.
0:11
We said cookiecutter pyramid starter. And it asked a few questions, and boom. Out popped a bunch of stuff.
0:17
One of the things we got, was this little test section. Now you can see, it's creating some view tests based on the built-in unit tests framework.
0:29
We could also use pytest. But it's using the built-in one. So we are going to use the built-in one as well just to be consistent.
0:35
But it really doesn't matter which framework you're using. And it's just doing standard things here. It's setting up and tearing down a few things.
0:42
And then it's testing one of the views. I noticed it's creating this testing.dummy_request. Where does that come from?
0:52
Pyramid. So pyramid has built-in testing capabilities to do things like give us either a fake request or a fake web app that it sort of spins up
1:02
out of its internals. And then here we're calling some what used to be a view method passing the request getting the model back from it.
1:10
Then we can test things like hey this model that comes back, does it have a project? I think this is maybe project details something to that effect.
1:19
Anyway this used to be a valid test. So here's how we're going to test. Some of it here you can see a more advanced version.
1:27
These are the whole web app. We're creating not just a test, a dummy request but a test web app based on our main method that we're calling
1:35
here from our __init__. So these are some of the things you're going to work with. But instead of just working with these tests here
1:43
we're going to go and do something better. We're going to organize this into things that are focused around our controllers and grouped in that way.
1:52
Let's go over here and say new package, I guess. And we will call this tests. And we'll leave this one here for a moment. Eventually we'll delete it.
2:02
But for now, lets just leave it as an example. And let's focus initially on the account. So remember to create different test files
2:11
for the various controllers, I will call it account_test. And we're going to get started by importing unittest and creating a testcase.
2:25
And the way this works in this framework is everything derives from testcase. And then it has methods that are test something.
2:34
All of these test_ whatever methods will be run by the test framework. Okay. So let's suppose we want to test register
2:46
validation, valid. I want to do valid one. I want to do another one that'll say no email let's say. Let's do this first one here.
2:58
Now I'm going to arrange these tests structure them in a way that I think is a pretty good pneumonic for folks.
3:06
It's going to use what's called the 3 A's. The 3 A's of testing. Which is Arrange, Act, then Assert. So we're going to do all of our setup.
3:18
Then we're going to do the one thing that we're trying to do, in this case validate our data. And then we're going to assert that it's valid
3:25
or something to that affect. Depending on whatever outcome we're after. So what's the arrange? Well let's arrange things by creating
3:33
one of these register view models. So it's going to be a register view model. Now, we could import this like so
3:43
where it goes up at the top. That's fine. However, look back over here. There's this, or the convention that they're using
3:52
where they're importing the dependencies only within the test. And the benefit there is that this only runs if we run the test.
4:00
It doesn't add any overhead. Where would the overhead come from? Well, if we look over here when we call config scan to go find all the routes
4:08
it's going to look through every file including the tests. And we want to isolate them as much as possible.
4:14
So we can do that by taking a step back here and say import locally, like that. So let's go over here and call this out as a range.
4:22
Great. Now we have to pass something. A request. Oh, where do we get that from? Well we sort of saw that before.
4:29
So we're going to go import pyramid.testing. And we'll get a dummy request. There's also sorts of things we can get.
4:40
Dummy session. Dummy rendering factory. We want a dummy request. And we're going to pass that request here. Now one thing that's a little annoying
4:49
remember on all of our view models we said this is a request. There's not a good enough base class that's shared across dummy request
4:58
and real request that describes all the things that happen there to make make the intellisense and whatnot useful. So this is going to complain.
5:06
And we can just say, no no this is going to be fine. Just don't check this. All right, so this arranges everything. Now we have to act vm.validate.
5:15
So validate the data. And then we have to assert. So self.assert is None. vm.error. So we want to say, there are not is not, is None. There we go.
5:31
We want to say there is no problem with this. And the way it's working right now it's not going to be so great. We're not done arranging.
5:40
We haven't passed any data. But let's just run this. See our test fail. It says that, you know, here's a string
5:46
that is, you know, is invalid in some sense. So let's try that. How do we run our test? Well, we can come over here and we can right click
5:55
and we can say run unit test in account. Let's do that. We're going to say run. We get a nice little test runner over here. This one that did nothing
6:03
oh, of course it passed. But this one, it failed with some errors. Let's see. It said, hm, in fact it just crashed
6:11
trying to do this. Look at that error. DBSession.factory execute that line right there. find_user_by_email is crashing because that is None.
6:25
And this really highlights one of the challenges that we're going to run into. We're trying to do this register thing and we want to validate it.
6:32
But this is actually going to the database. All right, but let's finish our arrange first. So in order to simulate submitting the form
6:40
we have to go to the request. And we got to go to Post. And we have to say this is going to be having an email, which is empty
6:48
and a password, wait, this is valid, right. Let's put some valid email there. The letter a, that's my favorite. All right so here's an email.
6:59
Here's a password. This should work. Let's run the test again. But we're getting this database thing. All right, whew, that's annoying.
7:08
We're going to come back and we're going to figure out how to fix that. But before we do, let's just do one more bit of overall organization.
7:15
If we split our test into multiple places here like we're going to have PackageController tests a lot of package tests we're going to have tests here
7:29
and we're going to have tests there. And we don't want to keep right clicking that it run these, no run those.
7:32
We want an ability to just say run them all. So let me show you really quick a technique we can use for that. Another file, _all_tests.
7:40
And what we can do is we can import all of the other tests. So we can import let's just do * and package_test.
7:53
We can PyCharm no no, let's just leave these alone. These are meant to be here. I know they look like they do nothing.
7:58
But they do something. And we can go run this. It's not going to come out as good as you think. So notice it doesn't even have
8:05
the ability to run unit tests. 'Cause PyCharm doesn't see it. So here's a super simple little hack we can do.
8:14
So we can just create this little, effectively empty test class. So PyCharm when we click over here says oh, running the test there.
8:23
And then it actually runs all tests which always always passes. But, then we see these others over here like that.
8:32
Yeah. So we'll be able to organize them from this. And that way we just add stuff here and just keep running the same command.
8:38
And we won't skip or accidentally overlook any of them. All right, with that in place we're ready to come back and work on this next.