• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Testing in Django
 

Testing in Django

on

  • 3,367 views

Slides from "Testing in Django", the Django Boston Meetup on January 17, 2013.

Slides from "Testing in Django", the Django Boston Meetup on January 17, 2013.

Statistics

Views

Total Views
3,367
Views on SlideShare
3,348
Embed Views
19

Actions

Likes
3
Downloads
33
Comments
2

3 Embeds 19

https://twitter.com 10
http://www.twylah.com 8
http://instacurate.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

12 of 2 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • You specify fixtures per TestCase, and they run on any test in that TestCase.

    class MyTest(TestCase):
    fixtures = ['this_fixture','that_fixture']

    def test_some_thing(self):
    # this test will run with those fixtures in the db


    -----------

    You could try this per test:

    def test_some_thing_else(self):
    self.fixtures = ['fixture_just_for_this_test']
    Are you sure you want to
    Your message goes here
    Processing…
  • Hi, great ppt! Very helpful as I know it's important, but don't know how to do it. About the fixtures, I was wondering how to use certain fixtures for certain tests, and if others are wondering about that as well: at the end of http://ericholscher.com/blog/2008/nov/5/introduction-pythondjango-testing-fixtures/ you can see how to select certain fixtures for certain tests.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Testing in Django Testing in Django Presentation Transcript

    • testing in django(browser-based testing too)17 january 2013Kevin Harvey@kevinharveykevin@storyandstructure.com
    • Who is this guy? Application Architect at story+structure Djangonaut since 2007 (version 0.96)For those of you who didn’t read the bio, I’m Kevin Harvey. I’m the Application Architect at story+structure. We’re based in Brookline and we do software for higher ed. I cut my teeth on Django 0.96in 2007 with djangobook.com
    • These are my twin sons Lane & Hank. They are almost 5 months old and awesome.
    • Who are y’all? A quick poll...I’d like to get an idea of who’s in the crowd tonight. If you would please raise your hand if you’ve: - ever started a Python interpreter in Terminal or Command Prompt - ever started a Django project (even just to play around) - gone through the “Polls” app in the Django docs (or feel that you could) - written a single automated test (even just to play around) - released or written a project with a good test suite
    • What is a test? An evolutionary perspectiveSo, what is a test? I’d like to answer that question from an evolutionary perspective.
    • What is a test? An evolutionary perspective def multiply_these_two_numbers(a,b): ! """ ! Add b to itself a times ! """ ! i = 0 ! product = 0 ! while a > i: ! ! product += b ! ! i += 1 ! return productLet’s say you wrote the function “multiply_these_two_numbers()”, which takes two arguments and addsthe second argument to itself by a factor of the first argument. It’s not pretty....
    • What is a test? An evolutionary perspective >>> from myapp.my_funcs import multiply_these_two_numbers >>> multiply_these_two_numbers(4,5) 20 >>> multiply_these_two_numbers(7,8) 56 >>> multiply_these_two_numbers(720,617) 444240... but it works! You can import it, you can give it two arguments, and it returns what you wouldexpect.
    • What is a test? An evolutionary perspective >>> from myapp.my_funcs import multiply_these_two_numbers >>> multiply_these_two_numbers(4,5) 20This is a test. No, it’s not automated, and yes you wrote it by hand in the terminal. But you did confirmthat the function: 1) was able to be imported, 2) took two arguments, and 3) returned the expected result.
    • What is a test? An evolutionary perspective from myapp.my_funcs import multiply_these_two_numbers import math def area_of_rectangle(length, width): ! """ ! Length times width ! """ ! return multiply_these_two_numbers(length, width) ! def surface_area_of_sphere(radius): ! """ ! 4 times pi times the radius squared ! """ ! radius_squared = multiply_these_two_numbers(radius, radius) ! four_times_pi = multiply_these_two_numbers(4, math.pi) ! return multiply_these_two_numbers(radius_squared, four_times_pi)You tell your colleagues about your new function, and they’re impressed. They start using yourfunction in other parts of the application.As the code base grows, you’re starting to realize how important your little function is.
    • What is a test? An evolutionary perspective from myapp.my_funcs import multiply_these_two_numbers print multiply_these_two_numbers(4,5) $ python my_tests.py 20 $As you find yourself checking that the function works more and more, you decide to save your test in afile called ‘my_tests.py’ with a print statement to verify the result. Now you can run this savedstatement whenever you want and know that your function is working.
    • What is a test? An evolutionary perspective >>> import time >>> time.sleep(604800)Weeks go by. You work on other parts of the project. You work on different projects. You code indifferent languages.
    • You have kids. Your mind is erased.
    • What is a test? An evolutionary perspective $ python my_tests.py 20 $You’ve totally forgotten the context for this test. What does ’20’ mean? You would have to look at thefile to see what the inputs were. In short, you don’t know whether this test passed or failed. Can’t wejust let Python handle all of this stuff, from setting up the test to remembering what the appropriateoutput should be?
    • What is a test? An evolutionary perspective from django.test import TestCase from myapp.my_funcs import multiply_these_two_numbers class SillyTest(TestCase): def test_multiply_these_two_numbers(self): """ Tests that the function knows how to do math """ self.assertEqual(multiply_these_two_numbers(4,5), 20)Enter Django’s TestCase with it’s assertEqual() method (based on Python’s own ‘assert’). Here we havea test that knows how to run itself, and knows whether it failed or not.
    • What is a test? An evolutionary perspective $ python manage.py test myapp Creating test database for alias default... . --------------------------------------------------------- Ran 1 test in 0.000s OK Destroying test database for alias default...Just as a primer, here’s what it looks like when we run that test and it passes. We’ll talk about runningtests and the output you get in a moment.
    • Why write tests? Why are we doing this?What’s the point of all these tests? At the outset, it looks like more work: - more code to write - more code to debug... but in fact, we write tests ....
    • Why write tests? 1. Drink More BeerTo drink more beer, or because we’re lazy. However you want to describe it, we write tests because wewant to fix stuff once and only once. Stop worrying about that rickety linchpin of a function holdingyour entire project together and write a test for it.
    • Why write tests? 2. Take the fear out of refactoringSpeaking of rickety functions, let’s look back at that awful function we wrote earlier.
    • Why write tests? UGLY CODE def multiply_these_two_numbers(a,b): ! """ ! Add b to itself a times ! """ ! i = 0 ! product = 0 ! while a > i: ! ! product += b ! ! i += 1 ! return productBleh. I’d love to fix this, wouldn’t you?
    • Why write tests? UGLY, VITAL CODE from myapp.my_funcs import multiply_these_two_numbers import math def area_of_rectangle(length, width): ! """ ! Length times width ! """ ! return multiply_these_two_numbers(length, width) ! def surface_area_of_sphere(radius): ! """ ! 4 times pi times the radius squared ! """ ! radius_squared = multiply_these_two_numbers(radius, radius) ! four_times_pi = multiply_these_two_numbers(4, math.pi) ! return multiply_these_two_numbers(radius_squared, four_times_pi)But it’s used everywhere in our app! What if we screw it up during the refactor?
    • Why write tests? UGLY, VITAL, TESTED CODE from django.test import TestCase from myapp.my_funcs import multiply_these_two_numbers class SillyTest(TestCase): def test_multiply_these_two_numbers(self): """ Tests that the function knows how to do math """ self.assertEqual(multiply_these_two_numbers(4,5), 20)This test (plus a couple more) severely limit the possibility that we’d screw up this function during arefactor. This test is a guarantee that the function, given two integers, will return the product of thosetwo integers.
    • Why write tests? BETTER CODE def multiply_these_two_numbers(a,b): ! """ ! Multiply a times b ! """ #! i = 0 #! product = 0 #! while a > i: #! ! product += b #! ! i += 1 #! return product ! return a*bSo refactor...
    • Why write tests? The test guarantees the refactor $ python manage.py test myapp Creating test database for alias default... . --------------------------------------------------------- Ran 1 test in 0.000s OK Destroying test database for alias default...... and run your tests. If the tests pass, you’re refactor works. Now wouldn’t it be nice if there weretests for all those other functions that your team wrote...
    • Why write tests? 3. Explain your codeGood tests will serve as technical documentation for your code. You can show your colleagues howyour code works by walking them through your tests. And get new developers up to speed quickly byexplaining how your tests work.
    • Why write tests? 4. Clarify your thinkingThis is sort of related to the last one, but for me writing tests really help me think through my app. Ifall my code gets tested, I know I’m only writing the code necessary to get the job done. Testing forcesyou to write code that’s more modular, which is easier to debug.
    • Why write tests? 5. Allow more developers to contributeThink back about the first version of our multiply function: that code was obviously written by a juniordeveloper. Kinda nasty, BUT IT WORKED. It got us from point a to point b. We moved forward becausethat junior developer contributed a function. We can hack faster because of the test, and we can goback and clean up the mess later.
    • Why write tests? 6. Be taken seriouslyAre you creating something you intend for other developers to use? The first thing I do whenevaluating a package from PyPI is check out the tests. It helps me to understand the code, and let’s meknow that the package is going to do what it’s supposed to do. It also gives me a glimpse into the way(or whether) the developer thought about the package during development.
    • Why write tests? 7. Try something out before you screw up your dev environmentThis is specific to Django, but I think it’s worth mentioning here.
    • Why write tests? Keep your dev database clean $ python manage.py test myapp Creating test database for alias default... . --------------------------------------------------------- Ran 1 test in 0.000s OK Destroying test database for alias default...Did you notice the “Creating test database” bit when we ran the test? Django tests create a databasefrom scratch for you every time you run them, and deletes the database when your done. That meansyou can write tests for new model fields and not have to do the syncdb/migrate/upgradedb dance.
    • Types of Tests 1. Functional tests 2. Unit tests 3. Performance tests (which I won’t cover)The differences between functional tests exist on a series of spectra.
    • What’s the Difference? Unit Functional Fewer things Many things (ideally one) (possibly all)Unit tests test a small number of things in your app. Functional tests test a lot.
    • What’s the Difference? Unit Functional Small, write many Big, write fewUnit tests are small and you’ll write a ton. Functional tests are big and you’ll write just a few.
    • What’s the Difference? Unit Functional Stuff developers Stuff users care about care aboutUnit tests in general cover things that developers are worried about. Functional tests test things userscare about.
    • What’s the Difference? Unit Functional Fast SlowUnit tests run fast (thousandths of a second). Functional tests run slow (seconds or more).
    • A few examples Django tests in action!
    • A few examples Unit test for Model def test_questions_increment_votes_up(self): ! """ ! Test voting up a question ! """ ! question_1 = Question(text="How can my team get started?", ! ! ! ! ! ! votes=7) ! ! ! ! ! ! ! question_1.increment_votes(4) ! ! self.assertEquals(question_1.votes, 11)Unit testing a model.
    • A few examples Unit test for Model class Question(models.Model): ! text = models.CharField("Question", max_length=500) ! votes = models.IntegerField() ! ! def increment_votes(self, num): ! ! self.votes += num ! ! self.save()This code makes the previous test pass.
    • A few examples Unit test for a Formdef test_question_form_excludes_all_but_text(self):! """! The user can only supply the text of a question! """! form = QuestionForm()! self.assertEquals(form.fields.keys(), [text])! self.assertNotEquals(form.fields.keys(), [text, votes])
    • A few examples Unit test for a Form class QuestionForm(forms.ModelForm): ! class Meta: ! ! ! model = Question ! ! ! fields = (text,)Make the previous form unit test pass.
    • A few examples Unit test for a POST actiondef test_ask_question(self):! """ ! Test that POSTing the right data will result in a new question! """! response = self.client.post(/ask/, {text: Is there any more pizza?})! !! self.assertRedirects(response, /)! !! self.assertEqual(Question.objects.filter(text=Is there anymore pizza?).count(), 1)
    • A few examples Unit test for a POST action urlpatterns = patterns(, ... url(r^ask/$, questions.views.ask, name=ask), ... def ask(request): if request.method == "POST": ! question_form = QuestionForm(request.POST) ! question_form.save() return HttpResponseRedirect(/)You have to edit two files to get the previous test to pass.
    • A few examples Functional test: Logging in def test_admin_can_manage_questions(self): self.browser.get(self.live_server_url + /admin/) ! ! username = self.browser.find_element_by_css_selector("input#id_username") username.clear() username.send_keys("peter") password = self.browser.find_element_by_css_selector("input#id_password") password.clear() password.send_keys("password") self.browser.find_element_by_css_selector("input[type=submit]").click() body = self.browser.find_element_by_tag_name(body) self.assertIn(Site administration, body.text)This test uses Selenium to test that an admin user is able to login in to the admin site.
    • A few examples Functional test: Logging in # set up the admin siteJust set up the admin site to get it to pass.
    • Test Driven Development What is Test Driven Development?Simply put, TDD means writing tests that fail and THEN writing the code to make them pass. Guardsagainst code explosion because you only write enough code to make the test pass.
    • TDD by ExampleOur example project: Torquemada
    • TDD by Example http://bit.ly/XHjcAi or http://infinite-meadow-8366.herokuapp.com/ Code https://github.com/kcharvey/testing-in-django or use the link at the demoSee the demo at either of the first URLs. The code is available on GitHub.
    • TDD by Example Our example project: Torquemada Torquemada allows attendees at “Testing in Django (browser based testing too)” to inquire of the presenter asynchronously. http://bit.ly/XHjcAiA description of the app we’ll be building.
    • TDD by Example Our example project: Torquemada Use Case: Isabella the Inquisitive Isabel has learned a lot by attending the “Testing in Django” MeetUp but still has a few questions for the presenter. She visits Torquemada in her web browser, where she can see if any of her inquiries have been addressed and see the question that is being currently discussed. She is able to ‘vote up’ questions she would like the presenter to answer, and ‘vote down’ questions she thinks are unimportant. She is also able to ask her own question. http://bit.ly/XHjcAiA use case for a user.
    • TDD by Example Our example project: Torquemada Use Case: Peter the Presenter Peter is presenting at the “Testing in Django” MeetUp and would like to answer any questions the attendees may have during set periods in the talk. He views Torquemada in his web browser to see what questions attendees have asked, including relative importance based on the number of votes they’ve received. When the group is discussing a question, he uses the Django admin site to set the question’s status to “Current”. After the question has been discussed, he sets the status to “Archived” http://bit.ly/XHjcAiA use case for an admin.
    • TDD by example Let’s do this.
    • Screencast 1 http://vimeo.com/57692050 (watch the video, then come back for the rest of the slides) 1) Set up a workspace 2) create a virtualenv 3) install django 4) startproject 5) startapp 6) test the app.You can start TDD on a Django project without even touching settings.py!
    • TDD by example from django.test import TestCase class SimpleTest(TestCase): Text def test_basic_addition(self): """ Tests that 1 + 1 always equals 2. """ self.assertEqual(1 + 1, 2)The test that ‘manage.py startapp’ generated.
    • Screencast 2 Text http://vimeo.com/57693303Replace the auto generated test with a meaningful one.
    • TDD by examplefrom django.test import LiveServerTestCasefrom selenium import webdriverclass QuestionsTest(LiveServerTestCase): Text def setUp(self): self.browser = webdriver.Firefox() self.browser.implicitly_wait(3) def tearDown(self): self.browser.quit()...Start with a functional test that tells (at least part of) a use case.
    • TDD by example...class QuestionsTest(LiveServerTestCase): ... def test_can_read_v..._a_question(self): Text browser and # Isabel opens her web # visits Torquemada self.browser.get(self.live_server_url + /) # TODO self.fail(finish this test)
    • Screencast 3 Text http://vimeo.com/57692852Extend the functional test with some use case as comments, and add a test for an h1 element.
    • TDD by example Text# She knows its Torquemada because she sees the name in the headingheading = self.browser.find_element_by_css_selector("h1#trq-heading")self.assertEqual(heading.text, "Torquemada")Here’s the assertion, using Selenium.
    • Screencast 4 Text https://vimeo.com/57693096Watch the new version of the functional test fail.
    • TDD by example We have a working (but failing) test. Commit it.Meaningful failure = important unit of work we’ve done. Let’s commit it.
    • TDD by example Let’s refactor a bit...
    • Screencast 5 Text http://vimeo.com/57693617Refactor the test.py file into a tests package.
    • TDD by example ... and commit that.
    • TDD by example So, where are we exactly?
    • Screencast 6 Text http://vimeo.com/57694735In the final screencast, we finish up this round of TDD: dive into a unit test for a view, write the code toget the test to pass, extend the unit test to cover more functionality, get it to pass, then confirm thatwe’ve satisfied our functional test (as it is).
    • TDD by example Rinse and repeat.Repeat the cycle of writing tests that fail (or extending tests to make them fail) and writing code tomake the tests pass.
    • How about a demo?
    • Getting Around with Selenium self.browser.get()This command (if you’ve set self.browser = webdriver.FireFox(), or something like it), does a GET toopen a web page with Selenium. It can open any URL.
    • Getting Around with Selenium self.browser.find_element_by_<METHOD>()Find elements on the page using one of Seleniums ‘find_element’ methods.
    • Getting Around with Selenium find_element_by_id find_element_by_name find_element_by_xpath find_element_by_link_text find_element_by_partial_link_text find_element_by_tag_name find_element_by_class_name find_element_by_css_selector # use this onefind_element_by_css_selector is my favorite. It feels like jQuery.
    • Getting Around with Selenium find_elements_by_id find_elements_by_name find_elements_by_xpath find_elements_by_link_text find_elements_by_partial_link_text find_elements_by_tag_name find_elements_by_class_name find_elements_by_css_selector # return Python listsYou can get lists of elements by pluralizing ‘elements’ in the method name.
    • Getting Around with Selenium element.click()Once you find an element, you can .click() it. This will behave just like a real user click, and respects anJavaScript event.preventDefault() handlers.
    • Getting Around with Selenium Working with form elements text_field = self.browser.find_element_by_css_selector("#id_text") text_field.clear() text_field.send_keys("Why arent you using reverse()?") self.browser.find_element_by_css_selector("input#trq-submit- question").click()Use .clear() and .send_keys() to type test into a form element.
    • How do I get started?I want to start testing on my team. What’s the best way?
    • How do I get started? 1. Write tests for bug reportsAn excellent way to start is to write tests for your bug reports. Find out the exact steps it takes toreproduce a problem and write either a functional or unit test THAT FAILS as an illustration of the bug.Then, fix the bug. Check in your fix and your test and rest easy knowing you’ve GUARANTEED that thebug is fixed.
    • How do I get started? 2. Use TDD for new featuresThere’s no time like the present to start writing tests. When your team decides on a new feature toimplement, start by writing some use cases and develop from a functional test.
    • How do I get started? 3. Write unit tests for existing code you use while doing 1. and 2.If you’re using a function from somewhere else in the system when you write code, you need to beable to guarantee that function does what you expect it to. Get in the habit of writing tests for parts ofyour project as you come in to contact with them, PARTICULARLY if they are involved in a bug fix.
    • What about continuous integration?Continuous integration tools automatically checkout our code, build it, and run the tests. It’s to protectourselves from developers on our team that forget to run the tests before they commit.
    • What about continuous integration? We’re trying out Jenkins.s+s is just starting to play with Jenkins, a CI platform in written in Java. NORMALLY, I’M LIKE...
    • .WAR
    • WHAT
    • IS
    • IT
    • GOOD
    • FOR?
    • What about continuous integration? But in this case I’ll make an exception.Jenkins is super easy to get up and running on your local machine, and there are plugins that play nicewith tools we’re all using.
    • Configuring Jenkins $ pip install django-jenkins INSTALLED_APPS = ( ... django_jenkins, ) ... JENKINS_TASKS = ( django_jenkins.tasks.run_pylint, django_jenkins.tasks.with_coverage, django_jenkins.tasks.django_tests, # there are more of these ) $ python manage.py jenkins # Jenkins will run this commanddjango-jenkins is a plugin that runs out tests and outputs the files Jenkins needs to show our buildstats. pip install and add just a few lines to your settings.py
    • Configuring Jenkins $ wget http://mirrors.jenkins-ci.org/war/latest/jenkins.war $ java -jar jenkins.war http://localhost:8080Just get the .war file, run it, and hit port 8080 on your machine.
    • Configuring Jenkins You’ll need some plugins: - Jenkins Violations Plugin - Jenkins Git Plugin - Jenkins Cobertura PluginInstall a few plugins.
    • Configuring Jenkins 1. Configure a new test (name, description) 2. Give it your repo URL 3. Tell it how often to build 4. Tell it the commands to run 5. Configure where to save the reports 6. Click “Build Now”Check out the tutorials in the “Resources” section of this slide deck for more on configuring your repo.It’ll take about 15 minutes the first time.
    • Configuring Jenkins DONEThat’s it.
    • Next Steps 508 compliance http://wave.webaim.org/toolbar JavaScript Testing Doctest.js http://doctestjs.org/There are things we definitely didn’t test. We’re looking into automated 508 compliance testing. Ifyou’re working in higher ed or the non-profit world, a non-compliant template should definitley“break the build”.
    • Resources Tutorials• http://www.tdd-django-tutorial.com/• http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/ (and part 2)•http://code.google.com/p/selenium/wiki/IPhoneDriver
    • Resources Jenkins• https://github.com/kmmbvnr/django-jenkins• https://sites.google.com/site/kmmbvnr/home/django-jenkins-tutorial• http://jenkins-ci.org/
    • Resources Performance Testing• http://funkload.nuxeo.org/• http://jmeter.apache.org/• http://httpd.apache.org/docs/2.2/programs/ab.html
    • Using fixtures Manage data for tests runsSometimes you want to create models explicitly. Other times you want to create a lot of reusable data.Enter fixtures.
    • [ Using fixtures { "pk": 1, "model": "questions.question", "fields": { "status": "new", "text": "How can my team get started with testing?", "votes": 0, "created": "2013-01-17T16:15:37.786Z" } }, { "pk": 2, "model": "questions.question", "fields": { "status": "new", "text": "Does Selenium only work in Firefox?", "votes": 0, "created": "2013-01-17T16:17:48.381Z" } } ]A fixture is just structured data (defaulting to JSON) that Django knows how to import and export: - loaddata - dumpdata
    • Using fixtures Do NOT try to write fixtures by hand $ python manage.py runserver ... # Use the Django /admin site to make some test data ... $ mkdir questions/fixtures/ $ python manage.py dumpdata questions --indent=4 > questions/fixtures/questions.jsonUse the admin site and ‘manage.py dumpdata’ to make fixtures easily.