One of the most common practices I came across while learning Rails is the flash[:notice] mechanism used to send (error) messages to the template. Consequently it was also one of my first targets to migrate when I started moving a pet application from Rails to Django.
I came up with a simple (and all too obvious) way to send error messages to the template. I am sure that there are better ways to do this. If you know of any, please take a minute to share them.
First, the Rails snippet.
Next, the equivalent in Django.
The template in Rails ...
... and the template in Django.
While testing in Django, flash can be treated just like any other context variable.
Wednesday, February 14, 2007
Request to Blogger
Please, please add a formatting tool/plug in/some other mechanism to highlight code syntax. It took me two frustrating hours of cutting and pasting to add code samples to this post. Even now, I am not completely happy with the results. And as automatically inserted line breaks (BR tags) and highlighter do not go together, I have to manually insert BR tags in all my posts :( Thankfully, I am not a prolific blogger ;) but even then it sucks.
I am not partial to any specific utility. In this case I followed the example set by other bloggers and used dp.SyntaxHighlighter. But I will (and so will most others, I suspect) gladly use your tool if you were to provide one.
C'mon guys, after all you are Google :)
I am not partial to any specific utility. In this case I followed the example set by other bloggers and used dp.SyntaxHighlighter. But I will (and so will most others, I suspect) gladly use your tool if you were to provide one.
C'mon guys, after all you are Google :)
Tuesday, February 13, 2007
Moving from Rails to Django: Migrating Tests
Context
I am in the process of migrating one of my small "pet" applications developed in Ruby on Rails to Python using Django. One of my first concerns was migrating tests, both unit (testing models) and functional (testing 'controllers' in Rails/'views' in Django) from one framework to the other. After looking around the documentation, asking questions and conducting some experiments I have some answers. Here is a listing of what I have found out so far.
Note
These examples will only work with the latest development version of Django.
Locating your tests
Rails
Usually located under the path [path_to_app]/test/functional/. There is usually one test source per controller, named as [controller_source_without_extension]_test.rb. For example if the source for a controller, say, 'Generator' is written in [path_to_app]/app/controllers/generator_controller.rb, then the corresponding test should be present in a file named generator_controller_test.rb
Django
The easiest way (see the official documentation) is to add all your tests to a file called tests.py and drop it in the application folder, at the same level as your models.py and views.py.
However I prefer to have a separate test source structure if I can help it. This has the added advantage of keeping I decided to adopt the convention used by Rails and came up with the following tree:
Fixtures
Fixtures are readily available in Rails. There are not quite there yet in Django and I am as righteously angry as the next ex-Rails user ;) But do not worry, they are on their way and will be available shortly. I am experimenting with a really dirty solution in the meantime. More on this in a subsequent post.
Writing Tests - setup
Rails
A typical setup() method in Rails looks like this: Django
The framework provides a test client to simulate browser calls. The best place to create a test client object would be the setup method.
Writing Tests - GET requests
Rails
My first objective was to test if a GET request to the controller/URL 'generator/index' was being handled properly. "Properly" in this case means three things:
Django
While the objectives remain the same, the steps vary. The key differences I noticed were:
Writing Tests - POST requests
Rails
A simple "happy path" POST request test looks like this in Rails: Here, in addition to checking the response I am also verifying that a particular session variable was set properly.
Django
Here again we find that there are no wrappers for session and that it is easy enough to add some. The session object itself is readily available and can be accessed using the test client.
Running Tests
Rails
The easiest way is to execute ./rake from the command line. There are separate tasks available (such as test:functional, for instance) in case you wish to run the functional tests only.
Django
The easiest way is to execute ./manage.py test from the command line. This will run the tests for all applications in the project. If you wish to test only one application, feed its name as an additional parameter.
Django Template Nuances
Django provides simple inheritance mechanism for templates. I personally like it :) What should be remembered is that using inheritance changes the testing process slightly. For instance, consider a view index that renders a template say, index.html. This template inherits from another, named base.html. A GET request test for the view would look like this: Note the difference from the earlier test. When template inheritance comes into play, response.template will resolve into a list of all the templates involved in the hierarchy, listed parent first. Corresponding to each template, there will be a separate context object at available at the same index in response.context (which will also resolve into a list)
I am in the process of migrating one of my small "pet" applications developed in Ruby on Rails to Python using Django. One of my first concerns was migrating tests, both unit (testing models) and functional (testing 'controllers' in Rails/'views' in Django) from one framework to the other. After looking around the documentation, asking questions and conducting some experiments I have some answers. Here is a listing of what I have found out so far.
Note
These examples will only work with the latest development version of Django.
Locating your tests
Rails
Usually located under the path [path_to_app]/test/functional/. There is usually one test source per controller, named as [controller_source_without_extension]_test.rb. For example if the source for a controller, say, 'Generator' is written in [path_to_app]/app/controllers/generator_controller.rb, then the corresponding test should be present in a file named generator_controller_test.rb
Django
The easiest way (see the official documentation) is to add all your tests to a file called tests.py and drop it in the application folder, at the same level as your models.py and views.py.
However I prefer to have a separate test source structure if I can help it. This has the added advantage of keeping I decided to adopt the convention used by Rails and came up with the following tree:
- [project]/[application]/test/functional/ for functional tests and
- [project]/[application]/test/unit/ for model tests.
Fixtures
Fixtures are readily available in Rails. There are not quite there yet in Django and I am as righteously angry as the next ex-Rails user ;) But do not worry, they are on their way and will be available shortly. I am experimenting with a really dirty solution in the meantime. More on this in a subsequent post.
Writing Tests - setup
Rails
A typical setup() method in Rails looks like this: Django
The framework provides a test client to simulate browser calls. The best place to create a test client object would be the setup method.
Writing Tests - GET requests
Rails
My first objective was to test if a GET request to the controller/URL 'generator/index' was being handled properly. "Properly" in this case means three things:
- Ensure that the response came back with an HTTP status of 200 OK;
- Ensure that the appropriate template was used; and
- Ensure that instance variables were present and had expected values.
Django
While the objectives remain the same, the steps vary. The key differences I noticed were:
- There are no built-in wrapper methods for GET/POST. It should be noted that it is easy to enough to code wrappers should one so wish.
- Likewise there are no equivalents for wrappers such as "assert_template" or "assert_response"
- Django uses a different philosophy when it comes to passing variables to templates. Instance variables are not directly passed to templates; rather they have to be explicitly passed using a context object or a call to locals()
Writing Tests - POST requests
Rails
A simple "happy path" POST request test looks like this in Rails: Here, in addition to checking the response I am also verifying that a particular session variable was set properly.
Django
Here again we find that there are no wrappers for session and that it is easy enough to add some. The session object itself is readily available and can be accessed using the test client.
Running Tests
Rails
The easiest way is to execute ./rake from the command line. There are separate tasks available (such as test:functional, for instance) in case you wish to run the functional tests only.
Django
The easiest way is to execute ./manage.py test from the command line. This will run the tests for all applications in the project. If you wish to test only one application, feed its name as an additional parameter.
Django Template Nuances
Django provides simple inheritance mechanism for templates. I personally like it :) What should be remembered is that using inheritance changes the testing process slightly. For instance, consider a view index that renders a template say, index.html. This template inherits from another, named base.html. A GET request test for the view would look like this: Note the difference from the earlier test. When template inheritance comes into play, response.template will resolve into a list of all the templates involved in the hierarchy, listed parent first. Corresponding to each template, there will be a separate context object at available at the same index in response.context (which will also resolve into a list)
Subscribe to:
Posts (Atom)