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