Building Data-Driven Web Apps with Pyramid and SQLAlchemy Transcripts
Chapter: Testing web apps
Lecture: Testing without the database

Login or purchase this course to watch this video and the rest of the course contents.
0:01 Things looked so good. We were about to test our simple little register view model but even just that, just testing the view model
0:10 turned out to unearth a serious, serious problem. Let's run it again. I can see it's failing. The failing is None type is not callable.
0:21 Well once you look into it you realize the DBSession.factory is not initialized because we've not set up the database.
0:29 Wait, we don't want to set up the database. Why is this using the database? This one we might be able to get away without the database.
0:36 Let's try. This one we're going to do it with no email. We make sure that there's an error and we can also assert that email is in that error.
0:49 Okay so we're expecting some kind of error message to be set like email is required. Right? So let's run that.
0:56 We don't need to call that out too explicitly there. Run it again, how are we doing? No sadly this one is also running into that problem.
1:10 If we structure it like this, if we just make that an L if which would be reasonable so the first time we hit an error we bail.
1:19 We probably could get one of these to pass, let's see. Yes, our no email came back and it did find that
1:29 it was an error set and the word email appeared in that error. But this one, this valid one, is never going to work without the database, okay.
1:39 We'll leave this one here. This one can go without the database but this one we're going to need a new technique.
1:46 I have to introduce you to a new idea here under this Act section. What we want to do is we want to go to the database
1:52 more importantly we want to go to this data service and this is why it's really awesome that we wrote this service separately
1:59 is we're calling this function find_user_by_email. How do I know? Here, oh now it says you must specify your name, okay.
2:06 So let's go and do that really quick. We'll get an error I was going to show you back. This will be name. There we go.
2:19 Now we get our None type error back. We go look, you can see it's calling find_user_by_email. Well the problem is it should be going to the database
2:29 to check that user. What we can do is we can use something called mocking. Mocking will change the behavior of this user
2:37 service module and this function in particular so let's go do that. We're going to use a context manager
2:42 so we only redefine it really narrowly within the context. So say with unittest.mock.patch. Oh we need to import that.
2:54 patch and then we're going to give it the target. The target is the full string name that we're looking for
3:00 so pypi.services.user_service.find_user_by_email. We're going to set the return value to be None, okay. I'm going to define that with block.
3:16 Let's make this a little more readable. And only in that little block when we call this one function does it not actually call that
3:26 find_user_by_email, but it just returns none for whatever values are passed in there. Okay now so this should work because
3:35 it's going to come back, validate is going to call this function, this function is going to return None to say hey there actually is no user
3:44 by that email address you thought so it should be fine. Let's try it again. How awesome is that? Oh my goodness. Okay so really really cool.
3:55 I'm going to expand it out and you can see it ran pretty quickly. Let's do one more test here. Let me duplicate this and do one other test.
4:03 register_validation_is_valid, I'll say existing user. So let's test what happens if we try to register
4:12 as an existing user and let's say that this user does exist. Say we're going to return a user which we have to import locally.
4:23 I still kind of like these up at the top in our arranged bit. I'm going to create this user and it doesn't really matter what we set here to the test.
4:30 It's just going to say we called that, a user came back so there must be an existing user with that email address. Now we're going to assert.
4:37 This is not None and existing is in the error. Let's give it a shot. So this way, we're controlling a different outcome for validate.
4:47 One more time. Boom look at that. Expanded out, existing user. All right, you want to see what the error is.
4:56 We could print out error just to see it real quick here. User already exists. Oh no we can't continue.
5:04 So that's how we're able to punch out these dependencies. We'll go in here and just for this little Act section
5:12 we are using a context block along with the patch aspect of unit testing to change the behavior of find_user_by_email.
5:23 We might have to do this for more than one method and that would be fine, but here we are. We're going to change this behavior this time to
5:31 return a new user so we can check for this validation case. Previously to say no there's no user with that email address
5:37 whatever you gave me, so validation should pass. Pretty awesome. We could use this for email systems or databases or
5:45 calling web services, calling purchase gateways. You name it, this allows us to get in the way of all these other dependencies that we have.
5:55 We saw that Pyramid itself supplies some testing primitives that we can use like our fake request that we can pass
6:03 to get our register view model up and running. That's how we test these view models. You can also see that's how we test the view methods as well.


Talk Python's Mastodon Michael Kennedy's Mastodon