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.

Talk Python's Mastodon Michael Kennedy's Mastodon