Created
March 15, 2014 04:26
-
-
Save sivaa/9561822 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#================ 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