Skip to content

Automatically test combinations of Python 2.7+, Django 1.6+, and DRF 3.1+ #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ pip-log.txt
pip-delete-this-directory.txt

# Pycharm project files
.idea/
.idea/

# Tox
.tox/
32 changes: 25 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,27 @@
language: python
sudo: false
python:
- "2.7"
- "3.3"
- "3.4"
install:
- pip install -e .
script: python runtests.py
install: pip install tox
script: tox
env:
- TOXENV=py27-django16-drf31
- TOXENV=py27-django16-drf32
- TOXENV=py32-django16-drf31
- TOXENV=py32-django16-drf32
- TOXENV=py33-django16-drf31
- TOXENV=py33-django16-drf32
- TOXENV=py27-django17-drf31
- TOXENV=py27-django17-drf32
- TOXENV=py32-django17-drf31
- TOXENV=py32-django17-drf32
- TOXENV=py33-django17-drf31
- TOXENV=py33-django17-drf32
- TOXENV=py34-django17-drf31
- TOXENV=py34-django17-drf32
- TOXENV=py27-django18-drf31
- TOXENV=py27-django18-drf32
- TOXENV=py32-django18-drf31
- TOXENV=py32-django18-drf32
- TOXENV=py33-django18-drf31
- TOXENV=py33-django18-drf32
- TOXENV=py34-django18-drf31
- TOXENV=py34-django18-drf32
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ like the following:

1. Python >= 2.7
2. Django
3. Django REST Framework >= 2.4
3. Django REST Framework >= 3.1

## Installation

Expand Down
6 changes: 4 additions & 2 deletions example/api/resources/identity.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.contrib.auth import models as auth_models
from django.utils import encoding

from rest_framework import viewsets, generics, renderers, parsers, serializers
from rest_framework.decorators import list_route, detail_route
from rest_framework.response import Response
Expand Down Expand Up @@ -31,8 +33,8 @@ def posts(self, request):
posts = [{'id': 1, 'title': 'Test Blog Post'}]

data = {
u'identities': IdentitySerializer(identities, many=True).data,
u'posts': PostSerializer(posts, many=True).data,
encoding.force_text('identities'): IdentitySerializer(identities, many=True).data,
encoding.force_text('posts'): PostSerializer(posts, many=True).data,
}
return Response(utils.format_keys(data, format_type='camelize'))

Expand Down
18 changes: 0 additions & 18 deletions example/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,18 +0,0 @@
"""
Example app URLs
"""
from django.conf.urls import patterns, include, url
from rest_framework import routers
from .resources.identity import Identity, GenericIdentity

router = routers.DefaultRouter(trailing_slash=False)

router.register(r'identities', Identity)

urlpatterns = router.urls

urlpatterns += patterns('',
url(r'identities/default/(?P<pk>\d+)',
GenericIdentity.as_view(), name='user-default'),
)

13 changes: 13 additions & 0 deletions example/factories/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals

import factory

from example.models import Blog


class BlogFactory(factory.django.DjangoModelFactory):
class Meta:
model = Blog

name = "Blog 1"
50 changes: 50 additions & 0 deletions example/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.utils.encoding import python_2_unicode_compatible


class BaseModel(models.Model):
"""
I hear RoR has this by default, who doesn't need these two fields!
"""
created_at = models.DateTimeField(auto_now_add=True)
modified_at = models.DateTimeField(auto_now=True)

class Meta:
abstract = True


@python_2_unicode_compatible
class Blog(BaseModel):
name = models.CharField(max_length=100)
tagline = models.TextField()

def __str__(self):
return self.name


@python_2_unicode_compatible
class Author(BaseModel):
name = models.CharField(max_length=50)
email = models.EmailField()

def __str__(self):
return self.name


@python_2_unicode_compatible
class Entry(BaseModel):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()

def __str__(self):
return self.headline
7 changes: 7 additions & 0 deletions example/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from rest_framework import serializers


class BlogSerializer(serializers.Serializer):

class Meta:
fields = ('name', )
4 changes: 2 additions & 2 deletions example/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
'django.contrib.auth',
'django.contrib.admin',
'rest_framework',
'example.api',
'example',
]

ROOT_URLCONF = 'example.api.urls'
ROOT_URLCONF = 'example.urls'

SECRET_KEY = 'abc123'

Expand Down
5 changes: 5 additions & 0 deletions example/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from pytest_factoryboy import register

from example.factories import BlogFactory

register(BlogFactory)
28 changes: 28 additions & 0 deletions example/tests/test_factories.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import pytest

from example.models import Blog
from example.factories import BlogFactory

pytestmark = pytest.mark.django_db


def test_factory_instance(blog_factory):

assert blog_factory == BlogFactory


def test_model_instance(blog):

assert isinstance(blog, Blog)


def test_blog_name(blog):
assert blog.name == 'Blog 1'


def test_multiple_blog(blog_factory):
another_blog = blog_factory(name='Cool Blog')
new_blog = blog_factory(name='Awesome Blog')

assert another_blog.name == 'Cool Blog'
assert new_blog.name == 'Awesome Blog'
50 changes: 32 additions & 18 deletions example/tests/test_format_keys.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import json

from example.tests import TestBase

from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse
from django.conf import settings
from django.utils import encoding

from example.tests import TestBase
from example.tests.utils import dump_json, redump_json


class FormatKeysSetTests(TestBase):
Expand All @@ -18,7 +18,8 @@ def setUp(self):
self.detail_url = reverse('user-detail', kwargs={'pk': self.miles.pk})

# Set the format keys settings.
setattr(settings, 'JSON_API_FORMAT_KEYS', 'camelization')
setattr(settings, 'JSON_API_FORMAT_KEYS', 'camelize')
# CAMELIZE capitalize the type, needs to be checked

def tearDown(self):
# Remove the format keys settings.
Expand All @@ -34,20 +35,33 @@ def test_camelization(self):

user = get_user_model().objects.all()[0]
expected = {
u'data': {
u'type': u'users',
u'id': user.pk,
u'attributes': {
u'firstName': user.first_name,
u'lastName': user.last_name,
u'email': user.email
},
'data': [
{
'type': 'Users',
'id': encoding.force_text(user.pk),
'attributes': {
'firstName': user.first_name,
'lastName': user.last_name,
'email': user.email
},
}
],
'links': {
'first': 'http://testserver/identities?page=1',
'last': 'http://testserver/identities?page=2',
'next': 'http://testserver/identities?page=2',
'prev': None
},
'meta': {
'pagination': {
'page': 1,
'pages': 2,
'count': 2
}
}
}

json_content = json.loads(response.content.decode('utf8'))
links = json_content.get('links')
content_dump = redump_json(response.content)
expected_dump = dump_json(expected)

self.assertEquals(expected.get('users'), json_content.get('users'))
self.assertEqual(u'http://testserver/identities?page=2',
links.get('next'))
assert expected_dump == content_dump
13 changes: 10 additions & 3 deletions example/tests/test_generic_validation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import json
from example.tests import TestBase

from django.core.urlresolvers import reverse
from django.conf import settings

from rest_framework.serializers import ValidationError

from example.tests import TestBase
from example.tests.utils import dump_json, redump_json


class GenericValidationTest(TestBase):
"""
Expand All @@ -20,7 +24,6 @@ def test_generic_validation_error(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 400)

result = json.loads(response.content.decode('utf8'))
expected = {
'errors': [{
'status': '400',
Expand All @@ -30,4 +33,8 @@ def test_generic_validation_error(self):
'detail': 'Oh nohs!'
}]
}
self.assertEqual(result, expected)

content_dump = redump_json(response.content)
expected_dump = dump_json(expected)

assert expected_dump == content_dump
Loading