Category Archives: General

CyanogenMod 11 on a Samsung Galaxy Note (N7000) – Nope!

It’s important to also publish negative results. So this as a memo to myself and a recommendation for others who would like to install CyanogenMod 11 on a Samsung Galaxy Note (N7000). Don’t do it. I installed it using the nightly build cm-11-20150817-NIGHTLY-n7000.zip and the Google Apss gapps-kk-20140606-signed.zip. The device reacted very slowly afterward and raised often error messages. I went back and installed CM 10 using cm-10.1.3-n7000.zip and gapps-jb-20130813-signed.zip. Back to happy.

Testing Django – part 1 – nose

The following series is meant to be a hands-on introduction to selected tools that can be used for automated Django testing. You can find all the parts here:

Intro

If you want to bring the good practice of automated testing or even Test Driven Development (TDD) to your Django project you have many different testing framework to choose from. In the first part of this series I want to introduce nose, in the second part we will have a look at Behavior Driven Development (BDD) with lettuce.

It is important to keep in mind that there are different levels of testing. The most important once are:

  1. unit testing
  2. integration testing
  3. system testing

Python‘s standard libraries and Django offer the unittest and doctest libs but I personally prefer the nose testing framework as it is powerful and has an easy syntax. Actually you can also use tests written for unittest or doctest and use nose a the test runner. You can even mix different types of testing styles. This is what I would call flexible.

Starting a project

Let’s start a little dummy project with one app. I am one of these folks who like to work with fruity examples:

$ django-admin.py startproject fruitsalad
$ cd fruitsalad/
$ django-admin.py startapp fruits

This should generate something that looks like this:

$ find 
.
./manage.py
./fruits
./fruits/views.py
./fruits/tests.py
./fruits/models.py
./fruits/__init__.py
./__init__.py
./settings.py
./urls.py

Set up the basic database information in the settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'fruit.db',
    }
}

Make manage.py executable

$ chmod u+x manage.py

and fire up the server:

$ ./manage.py runserver 
Validating models...
0 errors found

Django version 1.2.1, using settings 'fruitsalad.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

If you open http://127.0.0.1:8000/ in your browser you should get a welcome page.

Install nose and django-nose:

$ sudo pip install nose
$ sudo pip install django-nose

In the settings.py we need to tell the Django project to load our app and django-nose:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'fruitsalad.fruits', # Add this
    'django_nose',  #  Add this                                                            
)

Additionally we have to specify nose as our test runner:

TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'

Testing models

Test drive development means to write first the test and then the functionality to fulfill the expectations. So let’s write the first unit tests with nose. For nose is does not matter where in project folder you put the tests. It will find them (if you name the classes and functions correctly – i.e. starting with “Test” or “test”, respectively) but when creating the fruits app the file fruits/tests.py was created. I think it’s a good location for our tests so I will use it. django-admin.py put a unittest and a docstring based test example into this file already but we want to use nose syntax for our tests. We copy the following text into the file:

from fruitsalad.fruits.models import Fruit
import nose.tools as nt

class TestFruit(object):

    def setup(self):
	self.fruit = Fruit()
        self.fruit.set_name("Papaya")
        self.fruit.set_color("orange")

    def test_color(self):
        nt.assert_equal(self.fruit.name, "Papaya")
	nt.assert_equal(self.fruit.color, "orange")

    def test_yumminess(self):
	nt.assert_true(self.fruit.is_yummy())

    def test_color_change(self):
	self.fruit.become_brown()
        nt.assert_equal(self.fruit.color, "brown")

    def teardown(self):
	self.fruit.disappear()

Here we have one test class that contains three test functions. nose offers different possibilities to compare the expectations with real results. In the example we use assert_equal (the two given argument have to be equal) and assert_true (the given argument has to be True) but there are many others. Check pydoc nose.tools or this page for further references. We also use the setup and the teardown method to prepare our testing environment before the tests and to clean it after the tests.

We can now run nose and see if it test fails. As we configured nose as test runner we can do this in the following way:

$ ./manage.py test

Now we have our tests which define our expected behaviour of the model. We continue by creating a model that satisfies these tests. We add the following to fruits/model.py:

from django.db import models

class Fruit(models.Model):

    name = models.CharField(max_length=50)
    color = models.CharField(max_length=50)

    def set_name(self, name):
        self.name = name

    def set_color(self, color):
        self.color = color

    def is_yummy(self):
        return(True)

    def become_brown(self):
        self.color = "brown"

    def disappear(self):
        self.color = "transparent"

Now it should be possible to run the tests successfully:

$ ./manage.py test
Creating test database 'default'...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table fruits_fruit
Installing index for auth.Permission model
Installing index for auth.Group_permissions model
Installing index for auth.User_user_permissions model
Installing index for auth.User_groups model
Installing index for auth.Message model
No fixtures found.
nosetests --verbosity 1
...
----------------------------------------------------------------------
Ran 3 tests in 0.002s

OK
Destroying test database 'default'...

If a test fails you get a message like this:

[...]
  File "/home/myuser/fruitsalad/../fruitsalad/fruits/tests.py", line 12, in test_color
    nt.assert_equal(self.fruit.name, "Kiwi")
AssertionError: 'Papaya' != 'Kiwi'

----------------------------------------------------------------------
Ran 6 tests in 0.012s

FAILED (failures=1)
Destroying test database 'default'...

Testing views

In the next step we are going to test the views of our app (if you are not a Djangonout so far: the expression “view” is used differently as in other web frameworks). This could be already see as integration testing as interaction between model and views could be tested here. But to keep it simple for this introduction we don’t use our models here but only let the views do the work. To access the views we use Django‘s Client class. We add the following test to our fruits/test.py file:

from django.test import Client

class TestFruitView(object):

    def setup(self):
        self.client = Client()

    def test_product_index(self):
        response = self.client.get("/fruits/")
        nt.assert_equal(response.content, "The index")

    def test_product_show(self):
        response = self.client.get("/fruits/papaya")
        nt.assert_equal(response.content, "Show the papaya page")

    def test_product_add(self):
        response = self.client.get("/fruits/add")
        nt.assert_equal(response.content, "Add a fruit")


A test run might return this now:

TemplateDoesNotExist: 404.html

----------------------------------------------------------------------
Ran 6 tests in 0.019s

FAILED (errors=3)
Destroying test database 'default'...

The first step to solve this is to specify our url pattern in the file url.py:

urlpatterns = patterns(
    '',
    (r'^fruits/add', 'fruits.views.add'),
    (r'^fruits/(\w+)', 'fruitsalad.fruits.views.show'),
    (r'^fruits/', 'fruitsalad.fruits.views.index')
)

Now our app knows which view should be accessed depending on the requested url. Still we get errors:

TemplateDoesNotExist: 404.html

----------------------------------------------------------------------
Ran 6 tests in 0.020s

FAILED (errors=3)
Destroying test database 'default'...

This is due to the fact that the views don’t exits so far – what we will change now. We adapt the fruits/views.py to look like this:

from django.http import HttpResponse

def index(request):
    return HttpResponse("The index")

def show(request, fruit):
    return HttpResponse("Show the %s page" % fruit)

def add(request):
    return HttpResponse("Add a fruit")

Now the new tests run successfully.

Destroying test database 'default'...
kuf@yersinia $ ./manage.py test
Creating test database 'default'...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table fruits_fruit
Installing index for auth.Permission model
Installing index for auth.Group_permissions model
Installing index for auth.User_user_permissions model
Installing index for auth.User_groups model
Installing index for auth.Message model
No fixtures found.
nosetests --verbosity 1
......
----------------------------------------------------------------------
Ran 6 tests in 0.013s

OK
Destroying test database 'default'...

I hope you got a basic understanding how to test your Django app with nose. In the second part we will dive into the testing of our project with lettuce.