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.
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.