Building Data-Driven Web Apps with Pyramid and SQLAlchemy Transcripts
Chapter: Testing web apps
Lecture: Testing the full web app
0:00 Now we're going to look at functional tests. The idea is we're going to create a fake HTTP request like just this URL or something
0:08 and let the entire web app process it. So it's going to use the routing to find the right view it's going to call the right view with everything set up
0:17 that was done in the __init__ and so on. And we want to test that result. We don't have any home page test.
0:24 Let's just test this view right here, this home index. So we'll add another. Home test. And again, we're going to do all the import.
0:36 That's enough to start. I'll create a class called HomeControllerTest. And now, we're going to put a little more infrastructure
0:45 in place to support this. So let's say have a __init__. And here we're going to have a self.app which right now is None.
0:53 And then we're going to have a setup. It's not very Pythonic, look at the naming but whatever, it's fine. We're going to call setup here.
1:01 And then we actually want to go and get its main startup method which is right there. We want to get that. I'm going to call it
1:11 and it's going to do all the stuff. Set up our database, routing, and create the app and so on. So how's that going to work? We so we from pypi
1:20 import main well there's that function and we're going to say app equals main of nothing. We could pass a bunch of settings, but we're not.
1:30 Then we want to wrap this thing in a test WSGI app. So we'll say from webtest which apparently we don't have installed.
1:40 Notice over here our test requires said we need these things. So let's go pip install webtest and pytest-cov.
1:51 Looks like that worked. Great, and then now we're going to say import testapp. And then finally we'll say our app is this testapp wrapping around that.
2:04 So what's the idea here? Well, we're going to, every time we run a test it's going to run setup for us which will ultimately populate that.
2:13 So we're going to already have this in place and we can just use it. So in some sense this is going to be our Arrange to a large degree, okay?
2:21 Now, let's write a test. So we're going to test our home page here. Now, this works pretty easily. So we're going to say respond equals self.app.
2:30 Let's go here and give it a type. That gives us more details, doesn't it? Do a get and / with the status, 200 is what we're expecting.
2:48 Let's say we're expecting 404. Let's go ahead and run that. Now, if I just run this again it's not going to come out as amazing as you hope.
2:55 Passed, and you know what? Where's our home test? Well, remember, any time you add a new set of tests you're going to go and do this.
3:05 And so we have our home. Oh, it did not like it there. Let's see what's going on. I messed up the init actually trying to make it a little bit nicer
3:16 'cause I don't like defining this here without having it in the init, but We're just going to run it like that.
3:24 Failed, what did we get? What is the error? There's a whole bunch of HTML. That looks like HTML we wrote, doesn't it?
3:30 All right, what's the error, though? Way up at the top. It didn't really say why it failed. But, it failed because it actually got data
3:39 and not a 404. It got a 200 status code, not a 404. Let's try one more time. Perfect, it worked great.
3:47 This is just a warning about the type of constraint that we set up. It wanted a slightly different syntax. It's fine. Now, over here is a response.
3:55 Now, let's just print out what the heck is this? This response thing? So let's print out the type and the response, and run it again.
4:03 Look at this. The response is the string and it's a test response. Whew. The value is 200 and the text is so on. So if you want a little help with the
4:14 values you can work with we can have that here like so. So what are we going to start? We're going to say self.assert.
4:23 We've already asserted the status code is 200. So that's a good start. Let's say we're going to assert that some piece of text is in here.
4:31 And, let's just look at the output again. Let's assert, that, just that text is in there. So we want to assert that this text is in response.body.
4:44 Now, it turns out, I think we might have to put binary. I think this is not a string but let's just run it and see if it works.
4:51 No, so we have to convert that to a binary string and now it passes. Because this is not decoded text. It's just the binary response
5:02 that is the encoded utf-8 response. Okay, great. It looks like our tests are going here. So how is this different? Well, a couple of things.
5:10 We're actually calling the whole main and then wrapping it in a test app and doing this. It's worth pointing out that when we do that bit right there
5:19 that configures the database. That runs this stuff right here it's going to initialize it and, when we call this
5:29 it's going to use the routing to find the HomeController to call the home index, over here that's going to use the database.
5:36 So you may want to mock out or patch those four methods right there maybe even the global init for the database. I don't know.
5:45 So, you might need to do a little more work to make this independent but we're just going to stop here.
5:48 We've already gone through that patching process twice. And this is more complicated 'cause it using more of the app
5:54 but the same basic process up here would work. Now, you have to be a little more careful because we have just a context manager thing.
6:04 We might want to move, you know move this stuff down into here where we could use a context manager or that we clean those up.
6:12 So, either way, you want to be really careful about mocking right here 'cause it may not persist over here. If you use a with block
6:19 or it may be having too much of effect if you don't.