Skip to content

Instantly share code, notes, and snippets.

@sivaa
Created March 15, 2014 04:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sivaa/9561822 to your computer and use it in GitHub Desktop.
Save sivaa/9561822 to your computer and use it in GitHub Desktop.
#================ PART - 0 - PRE-REQUISTES ================
# Install Django and Selenium
# Create a Django Project and add a package called functional_test
#================ PART - 1 - GETTING READY ================
# Step 1: Check if the server is running
from selenium import webdriver
browser = webdriver.Firefox()
browser.get("localhost:8000")
# Step 2: Check 'Django' in title
assert 'Django' in browser.title
# Step 3: Check 'To-Do' in title
assert 'Movie' in browser.title
# Step 4: # Print useful information to the user
assert 'Movie' in browser.title, "The current title is " + browser.title
# Step 5: Close the browser once the tests are done
browser.quit()
# Step 6: Using try/catch to close the browser always
try:
assert 'Movie' in browser.title, "The current title is " + browser.title
finally:
browser.quit()
# Step 7: use unittest module TestCase class
from selenium import webdriver
import unittest
class FirstUserTest(unittest.TestCase):
def setUp(self):
self.browser = webdriver.Firefox()
def tearDown(self):
self.browser.quit()
def test_add_a_movie_and_fetch_it(self):
self.browser.get("localhost:8000")
self.assertIn("Movie", self.browser.title)
self.fail("Finish the Test")
if __name__ == '__main__':
unittest.main()
# Step 8: Wait for 3 seconds and look for data
self.browser.implicitly_wait(3)
# Step 9: Write a unit test using Django Unit Test Framework (Create movie app)
class DemoTest(TestCase):
def test_addition(self):
self.assertEqual(10 + 10, 25)
# $ python manage.py test
#================ PART - 2 - GETTING DIRTY ================
# Step 1: Retry to resolve the home page to correct view - unit test
from django.test import TestCase
from django.core.urlresolvers import resolve
from myapp.views import home_page
class HomePageTest(TestCase):
def test_home_page_url_resolve(self):
found = resolve("/")
self.assertEqual(found.func, home_page)
# Step 2: Make the home_page = None and run the test
home_page = None
# Step 3: Fix the urls.py and test again
url(r'^$', 'myapp.views.home_page', name='home'),
# Step 4: Fix the urls.py and test again
def home_page():
pass
# Step 5: Test the home page HTML content
from django.http.request import HttpRequest
def test_home_page_html_content(self):
request = HttpRequest()
response = home_page(request)
self.assertTrue(response.content.startswith("<html>"))
self.assertTrue(response.content.endswith("</html>"))
self.assertIn("<title>Movie List</title>", response.content)
# Step 6: Fix the arguments in the home page view
def home_page(request):
pass
# Step 7: Fix the return type
from django.http.response import HttpResponse
def home_page(request):
return HttpResponse()
# Step 8: Fix the first assertion error <html>
return HttpResponse("<html>")
# Step 9: Fix the second assertion error </html>
return HttpResponse("<html></html>")
# Step 10: Fix the last assertion error - title
return HttpResponse("<html><head><title>Movie List</title></head></html>")
# We learned so far
# • Starting a Django app
# • The Django unit test runner
# • The difference between FTs and unit tests
# • Django url resolving and urls.py
# • Django view functions, request and response objects
# • And returning basic HTML
#================ PART - 3 - Lets Build ================
# Step 1: Enhance your requirements in the functional test
# Step 1.1: Add comments based on the requirements
def test_add_a_movie_and_fetch_it(self):
self.browser.get("localhost:8000")
# Check the title
self.assertIn("Movie", self.browser.title)
# Check the heading
# Check the input text box
# Add a movie name using that text box
# Check that movie name in the list table
# Add one more movie name and Check that movie name in the list table
# Step 1.2: Implement the functional testing for heading
# Check the heading
heading = self.browser.find_element_by_tag_name("h1").text
self.assertIn("Movie", heading)
# Step 1.3: Implement the functional testing for input text box
# Check the input text box
input_box = self.browser.find_element_by_id("id_movie_name")
input_box_place_holder = input_box.get_attribute("placeholder")
self.assertEqual(input_box_place_holder, "Enter a Movie Name")
# Step 1.4: Implement the functional testing for adding movie name
# Add a movie name in that text box
from selenium.webdriver.common.keys import Keys
input_box.send_keys("Troy")
input_box.send_keys(Keys.ENTER)
# Step 1.5: Implement the functional testing for verifying the added movie name
# Check that movie name in the list table
table = self.browser.find_element_by_id("id_movie_list_table")
rows = table.find_elements_by_tag_name("tr")
self.assertTrue(any("Troy" in row.text for row in rows))
# Step 1.6: Implement the functional testing for adding movie name and verify the same
# Add one more movie name and Check that movie name in the list table
input_box.send_keys("Terminator")
input_box.send_keys(Keys.ENTER)
self.assertTrue(any("Terminator" in row.text for row in rows))
# Step 2: Lets re-factor the HTML code (to templates)
# Inside your app directory create templates/home.html
<html>
<head>
<title>Movie List</title>
</head>
</html>
# Change the views.py
def home_page(request):
return render(request, "home.html")
# Run and fix the test issues
# Step 3: Use render to render_to_string
def test_home_page_html_content(self):
# ...
expected_html = render_to_string("home.html")
self.assertEqual(response.content, expected_html)
# Step 4: Implement the heading text in the template
<body>
<h1>My Movie List</h1>
</body>
# Run the functional test and make it pass for heading tag
# Step 5: Implement the input box
<input id="id_movie_name"/>
# Step 6: Implement the place holder for the input box
<input id="id_movie_name" placeholder="Enter a Movie Name"/>
# Step 7: Add the movie list table
<table id="id_movie_list_table"> </table>
# Step 8: Make the error message
self.assertTrue(any("Troy" in row.text for row in rows), "Movie Troy is not added to the table")
# Step 9: Lets send the movie name to server. Form POST.
<form method="POST">
<input id="id_movie_name" placeholder="Enter a Movie Name"/>
</form>
# Step 10: Add delay to view the read the error
# Check that movie name in the list table
import time
time.sleep(20)
table = self.browser.find_element_by_id("id_movie_list_table")
# Step 11: Fix the issue with csrf_token
<form method="POST"> {% csrf_token %}
# Step 12: Lets implement the save and return. Start with unit test
def test_movie_save_post_content_and_return(self):
request = HttpRequest()
request.method = 'POST'
request.POST['movie_name'] = 'Troy'
response = home_page(request)
self.assertIn("Troy", response.content)
# Step 13: Lets fix that by enhancing the views.py
def home_page(request):
if request.method == 'POST':
movie_name = request.POST['movie_name']
return HttpResponse(movie_name)
return render(request, "home.html")
# Step 14: Actual fix. Return the movie from template
<table id="id_movie_list_table">
<tr> <td> {{ movie_name }} </td> </tr>
</table>
# Step 15: Enhance the test case to test the same.
expected_html = render_to_string("home.html", {'movie_name': 'Troy'})
self.assertEqual(response.content, expected_html)
# Step 16: Fix it in the view by passing the required variables
if request.method == 'POST':
movie_name = request.POST['movie_name']
return render(request, "home.html", {'movie_name': movie_name})
return render(request, "home.html")
# Step 17: Re-factor it by removing the method checking
movie_name = request.POST['movie_name']
return render(request, "home.html", {'movie_name': movie_name})
# Step 18: Fix the key error
movie_name = request.POST.get('movie_name', "")
# Step 19: Run the FT. Add more more info to debug the failure
self.assertTrue(any("Troy" in row.text for row in rows),
"Movie Troy is not added to the table. Table content: %s" % (table.text))
# Step 20: If the table content is empty, add delay and check the source
time.sleep(60)
# The table might have the empty data
# Step 21: Fix it in the template
<input id="id_movie_name" name ="movie_name" placeholder="Enter a Movie Name"/>
# Step 22: Debug the failure for adding second movie name
# Fix it in the functional test
input_box = self.browser.find_element_by_id("id_movie_name")
input_box.send_keys("Terminator")
input_box.send_keys(Keys.ENTER)
# Fix the same issue for table
table = self.browser.find_element_by_id("id_movie_list_table")
rows = table.find_elements_by_tag_name("tr")
# Step 23: Duplicate Code. Refactor it
def add_content_in_movie_name_input_box(self, content):
input_box = self.browser.find_element_by_id("id_movie_name")
input_box.send_keys(content)
input_box.send_keys(Keys.ENTER)
def check_content_in_movie_list_table(self, content):
table = self.browser.find_element_by_id("id_movie_list_table")
rows = table.find_elements_by_tag_name("tr")
time.sleep(2)
self.assertTrue(any(content in row.text for row in rows),
"Movie %s is not added to the table. Table content: %s" % (content, table.text))
# Add a movie name in that text box
self.add_content_in_movie_name_input_box("Troy")
# Check that movie name in the list table
self.check_content_in_movie_list_table("Troy")
# Add one more movie name and Check that movie name in the list table
self.add_content_in_movie_name_input_box("Terminator")
self.check_content_in_movie_list_table("Terminator")
#================ PART - 4 - Lets Persist ================
# (Integration Test)
# Step 1: Write unit test for movie model
from myapp.models import Movie
class MovieModelTest(TestCase):
def test_save_and_retrieve_movies(self):
movie_troy = "Troy"
movie_terminator = "Terminator"
Movie.objects.create(name = movie_troy)
Movie.objects.create(name = movie_terminator)
movies = Movie.objects.all()
self.assertEqual(movies.count(), 2)
self.assertEqual(movie_troy, movies[0].name)
self.assertEqual(movie_terminator, movies[1].name)
# Step 2: Fix the import error by adding a model
# models.py
class Movie():
pass
# Step 3: Fix the Model Manager error by inherting a models.Model
class Movie(models.Model):
# Step 4: Fix the fields not found issue by adding it
name = models.CharField(max_length=100)
# Step 5: PRACTICE: Add a test for avoid duplicate and fix it.
# PRACTICE CODE
name = models.CharField(max_length=100, unique = True)
# Step 6: PRACTICE: Add a test for zero and max length and fix it.
# PRACTICE CODE
# Step 7: Add unit test to verify from HTML POST to model save.
# At the end of
def test_movie_save_post_content_and_return(self):
self.assertEqual(Movie.objects.count(), 1)
self.assertEqual(Movie.objects.first().name, "Troy")
# Step 8: Fix the same by reading the POST and save it to database
Movie.objects.create(name = movie_name)
# Step 9: Add unit test to check GET requests
# In HomePageTest class
def test_movie_get_request_not_save_content(self):
request = HttpRequest()
request.method = 'GET'
home_page(request)
self.assertEqual(Movie.objects.count(), 0)
# Step 10: Fix the same by ignore it
if request.method == 'GET':
return render(request, "home.html")
elif request.method == 'POST':
movie_name = request.POST.get('movie_name', "")
Movie.objects.create(name = movie_name)
return render(request, "home.html", {'movie_name': movie_name})
else:
return HttpResponse("NOT SUPPORTED")
# Step 11: Something might have broken in other tests. Fix it
# def test_home_page_html_content(self):
request.method = 'GET'
# Step 12: POST should perform a redirection. Add a unit test for it
def test_movie_save_post_content_and_redirect(self):
request = HttpRequest()
request.method = 'POST'
request.POST['movie_name'] = 'Troy'
response = home_page(request)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], "/")
# Step 13: Fix 200 to 302 in the views
from django.shortcuts import redirect
return redirect("/")
# Step 14: OOPS. Something failed. POST didn't return the movie name.
# Its an invalid test now after refactoring. remove it
self.assertIn("Troy", response.content)
expected_html = render_to_string("home.html", {'movies': 'Troy'})
self.assertEqual(response.content, expected_html)
# Step 15: Enhance the unit test case to verify the list of movies
def test_movie_list_in_table(self):
Movie.objects.create(name = "Troy")
Movie.objects.create(name = "Terminator")
request = HttpRequest()
request.method = 'GET'
response = home_page(request)
self.assertIn("Troy", response.content)
self.assertIn("Terminator", response.content)
# Step 16: Fix the same.
if request.method == 'GET':
movies = Movie.objects.all()
return render(request, "home.html", {'movies': movies})
{% for movie in movies %}
<tr> <td> {{ movie.name }} </td> </tr>
{% endfor %}
# Step 17: Lets run the function test. It fails. Sync/Create the DB.
python manage.py syncdb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment