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