Register a user
The first thing we need to do with users: registering them. Luckily web2py comes with on-board resources, that provides most we need.
Remember the mockup for the Register Form from section 4.2
Compare the mockup to the Register page at http://localhost:8000/tukker/user/register
The Register page looks pretty similar to what we want to achieve, but to suit it our needs we will have to do some improvements:
For the Tukker.Me application, John wants users to have a user name that is unique, the email address alone is not sufficient for us. Imagine @email@example.com in a direct Tukker message - not very elegant. John wants something like @killerwebdev.
John wants that users are able to upload a profile picture.
Finally John wants us to style the Register page with proper margins and padding Creating the user with picture.
Testing the register form.
Before we go on we need to define tests for the register form. Unfortunately testing the Register form is not as simple as testing the static pages. When we register a user, we write it to the database. Because users need to be unique, we would have to write a new test for every test run or we would need to change the users with ervery test run - both solution don't seem very practical and trust worthy. We have another possibility, after every test run for the Register page, we will delete the user we created with the test run.
First, let us write some general tests, which we used allready with the static pages, that are important with the register page, too. Create a new file
fts/test_register_form.py and put in the first tests:
from functional_tests import FunctionalTest, ROOT
This is pretty much the same stuff we testet on our static pages, let's check if everything passes:
$ python functional_tests.py
Unfortunately we failed one test. Our registration page has the same title as the home page, but John wanted a better fitting title for the registration page. This is why we chose the title Tukker.Me Registration for the
To pass that test we need to know which function we must change. Let's have a look at the url of the registration page:
If you remember web2py's dispatching machanism from section 3.3, you should hava an idea which function should be responsible for the registration page :
For the sake of repetition let's do the dispatching for our registration page by hand:
- application = tuker
- controller = default
- function = user (Did you guess this?)
- args = register (What the hell are args?)
Ok, now we know the function we need to change is
user, but you might ask yourself: What are args?
args are the URL arguments behind the function name. Different parameters are divided by a forward slash:
http://hostname/application/controller/function/argument1/argument2/ - web2py maps these URL arguments to a Python list, that is provided by the
request.args variable :
request.args = [argument1, argument2, ...]
- we need to change the
userfunction in the
- we need to watch for the URL argument
- our title is wrong => we need to change the variable
With this knowledge it's quite easy to change the
we added only two lines to the
user function :
if request.args == "register":
looks, if the first item of the
request.args list is register.
If it's true, then we change the
response.title variable to Tukker.Me Registration.
Re-run the test and check if you pass all tests.
Now we will write a test for the register form. The test will pass, to make sure web2py's standard functionality is doing fine. I know: Tests should fail the first time, but we are using web2py's standard features without any customization - this time we can make an exception.
First make sure to add one more line to
This lets us use web2py'S features in our tests. Don't worry to much about it.
Here is the test code, add it to
The test finds every input in the firm and fills in values.
first_name = self.browser.find_element_by_name("first_name")
finds the element by its name - but what is the name of an element? Use Firebug to inspect the First Name input field of the register form. You will see something like this
name tag of input field makes it possible to connect certain labels to this input field.
After we selected the input field we put some value in it :
send_keys() method simulates keyboard input from the user.
We do this two steps for every input field in the register form. After we filled all input fields we simulate a click on the Register button :
register_button = self.browser.find_element_by_css_selector("#submit_record__row input")
This time we use a css selector to select the button (buttons have no name attribute) and use the
click() method to click on the button.
Finally we make the assertion that determinates if our test passes or fails :
welcome_message = self.browser.find_element_by_css_selector(".flash")
What are we testing here? We assume, if John's registration works, then he gets redirected to the homepage and on the homepage he sees a flash message Welcome to Tukker.Me.
Let's check if our test works :
$ python functional_tests.py
We created a user John Tukker, but what happens if we run the test again? :
$ python functional_tests.py
The test doesn't pass any more. That's because we can't register a second John Tukker. You can see the database entry if you login the admin area at http://localhost:8000/admin/design/tukker and click on database administration and then on db.auth_user. There it is: John Tukker, if you click on the id at the beginning of the row you get to a detailed view where you can mark a check box to delete the entry.
Next time the test should pass again. To prevent this problem from happening again, we need a way to delete John Tukker from our database after every succesfull test.
How can we do this? Remeber the
setUp() method at the beginning of any test class? We can use something similar at the and of our test class:
tearDown() work, we must import the the Python's
os.path module and web2py's
dal module, put :
in the first line of
test_register_form.py. Python modules are libraries that can be called from other Python scripts.
What are we doing here? First we build a path with the Python's
path module :
path_to_database = path.join(path.curdir, "databases")
join method puts together several path elements together to one big absolute path; the
curdir variable of the path module holds the current working directory we are (in our case the base directory of our app). The beauty of this solution is, that it works across all operating systems.
Then we connect to the database :
db = DAL('sqlite://storage.sqlite', folder=path_to_database)
In essence we do the same web2py does when we start it: we make a connection to the database with web2py's database abstraction layer (DAL) while we creating an instance of the
DAL class and then we import the database tables.
After that we look for database users with the email firstname.lastname@example.org :
db_query = db(db.auth_user.email == 'email@example.com').select()
The statement returns a list of of database entries with one or zero entries - hence there can be only on user in the database with the email adress firstname.lastname@example.org. Don't worry if you not fully understand the database query, we look into queries in more detail later.
Next we check if there length of
db_query is longer than zero, if this is true (it means we found something in the databse) we delete the entry and finally we commit the changes to the database :
if len(db_query) > 0:
That's it, we wrote the initial tests of our register page.
I hope this section wasn't to intimidating. I know testing is hard work, but it's worth the price. Your learned how to simulate user input on a web page and why you should clean up the database if you changed the databse during your test. In the next chapter we will think about our user model and refine our tests to suit our user model. We will then change our app to pass the tests.
Finally let's commit the changes to our repository:
hg commit -m"First tests for the register form"