Skip to content

Commit

Permalink
Merge pull request #18 from steelkiwi/readme_update
Browse files Browse the repository at this point in the history
Readme update
  • Loading branch information
geerk committed Oct 9, 2015
2 parents 774a2e3 + 8af489a commit f4fdb3c
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 135 deletions.
165 changes: 114 additions & 51 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@ django-skd-smoke
.. image:: https://coveralls.io/repos/steelkiwi/django-skd-smoke/badge.svg?branch=master&service=github
:target: https://coveralls.io/github/steelkiwi/django-skd-smoke?branch=master

.. image:: https://img.shields.io/pypi/l/django-skd-smoke.svg
:target: https://pypi.python.org/pypi/django-skd-smoke

.. image:: https://img.shields.io/pypi/v/django-skd-smoke.svg
:target: https://pypi.python.org/pypi/django-skd-smoke

.. image:: https://img.shields.io/pypi/pyversions/django-skd-smoke.svg
:target: https://pypi.python.org/pypi/django-skd-smoke

This package is intended for simplification of smoke tests creation.

.. contents::

Installation
------------

Expand All @@ -22,8 +33,9 @@ Usage
-----
After installation you should create new ``TestCase`` derived from
``skd_smoke.SmokeTestCase`` and define your smoke tests configuration.
Please review ``example_project`` directory which contains common django
project and demonstrates django-skd-smoke usage.
Please review `Examples`_ section which demonstrates different usecases.
They are related to ``example_project`` directory which contains common
django project.


Configuration
Expand All @@ -49,7 +61,7 @@ tuples for every request with the next structure:
- plain url or urlname as string
- Yes
* - status
- http status code (200, 404, etc.) as ``int``
- expected http status code (200, 404, etc.) as ``int``
- Yes
* - method
- http request method (GET, POST, etc.) as string
Expand Down Expand Up @@ -86,11 +98,14 @@ you can use it to transfer state between them. But take into account that
Examples
--------

All examples are taken from ``example_project`` package and can be run after
repository cloning.

\1. Demonstration of simple requests:
1. GET 200
2. GET 200 with request_data as dict
3. POST 201
4. POST 201 with request_data as callable
3. POST 200
4. POST 302 with request_data as callable
5. GET 302 (unauthorized access)
6. GET 200 (authorized access)
7. POST 405 (method not allowed)
Expand All @@ -102,60 +117,59 @@ Examples
from skd_smoke import SmokeTestCase
def get_new_object_data(testcase):
return {'title': 'new object',
'description': 'detailed object description'}
def get_article_data(testcase):
return {'headline': 'new article'}
def get_user_credentials(testcase):
UserModel = get_user_model()
username = 'test_user'
password = '1234'
new_user = UserModel.objects.create(username=username)
credentials = {'username': username, 'password': password}
User = get_user_model()
new_user = User.objects.create(username=username)
new_user.set_password(password)
new_user.save()
return {
'username': username,
'password': password
}
testcase.user = new_user
return credentials
class YourSmokeTests(SmokeTestCase):
class SimpleSmokeTestCase(SmokeTestCase):
TESTS_CONFIGURATION = (
('home', 200, 'GET',), # 1
('home', 200, 'GET', {'request_data': {'scrollTop': 1}} ), # 2
('create', 201, 'POST',), # 3
('create', 201, 'POST', {'request_data': get_new_object_data}), # 4
('profile', 302, 'GET',), # 5
('profile', 200, 'GET', {'user_credentials': get_user_credentials}), # 6
('/post_only/', 405, 'GET',), # 7
('home', 200, 'GET', {'request_data': {'scrollTop': 1}}), # 2
('articles:create', 200, 'POST',), # 3
('articles:create', 302, 'POST',
{'request_data': get_article_data}), # 4
('is_authenticated', 302, 'GET',), # 5
('is_authenticated', 200, 'GET',
{'user_credentials': get_user_credentials}), # 6
('/only_post_request/', 405, 'GET',), # 7
)
2. Usage of ``initialize`` callback to create several objects to test objects
list.

Suppose you want to make smoke test for model list page. Initially your test db
does not contain any objects. You can use ``initialize`` callback here to
create your objects.

Suppose you want to make smoke test for articles list page but initially your
test db does not contain any. You can use ``initialize`` callback here to
create several articles.

.. code-block:: python
from skd_smoke import SmokeTestCase
from ..models import SomeModel
from articles.models import Article
def create_list(testcase):
def create_articles(testcase):
for i in range(3):
SomeModel.objects.create()
Article.objects.create(headline='article #%s' % i)
class YourSmokeTests(SmokeTestCase):
class ArticlesListSmokeTestCase(SmokeTestCase):
TESTS_CONFIGURATION = (
('somemodel_list', 200, 'GET',
{'initialize': create_list} # pass your func here
('articles:articles', 200, 'GET',
{'initialize': create_articles} # pass your func here
),
)
Expand All @@ -169,54 +183,103 @@ pages.
from skd_smoke import SmokeTestCase
from ..models import SomeModel
class YourSmokeTests(SmokeTestCase):
class RedirectToSmokeTestCase(SmokeTestCase):
TESTS_CONFIGURATION = (
('profile', 302, 'GET', {
('is_authenticated', 302, 'GET', {
'redirect_to': '%s?next=%s' % (reverse('login'),
reverse('profile')),
reverse('is_authenticated')),
'comment': 'Anonymous profile access with check of redirect url'
}),
)
4. Usage of ``url_kwargs`` and ``user_credentials`` callbacks to test
authorized access of owner to newly created object.

Suppose you have a model which unpublished version can be viewed by its owner
only. You can test this situation by creating of user in ``url_kwargs``
callback and transfering user to ``user_credentials`` callback.
Suppose you have a model Article which unpublished version can be viewed by
its owner only. You can test this situation by creating of user in
``url_kwargs`` callback and transfering user to ``user_credentials`` callback.
Unfortunately, you cannot get password from user model cause it contains
hashed password. So you should return password as plain text.

Lets smoke test two other situations when 404 page is showed. Finally we have
three testcases:

i. Anonymous access should show 404 page.
ii. Some ordinary user access should also show 404 page.
iii. Only owner access returns actual article with status 200.

.. code-block:: python
from django.contrib.auth import get_user_model
from skd_smoke import SmokeTestCase
from ..models import SomeModel
from articles.models import Article
def create_object(testcase):
def create_user():
UserModel = get_user_model()
new_user = UserModel.objects.create(username='test_user')
new_user.set_password('1234')
new_user.save()
testcase.user = new_user
new_object = SomeModel.objects.create(owner=new_user)
return {'pk': new_object.pk}
return new_user
def get_user_credentials(testcase):
def create_unpublished_article(commit=True):
article = Article(headline='unpublished', published=False)
if commit:
article.save()
return article
def create_article_without_owner(testcase):
return {'pk': create_unpublished_article().pk}
def create_and_return_user_credentials(testcase):
user = create_user()
return {
'username': user.username,
'password': '1234' # User contains hashed password only so we should
# return it as plain text
}
def create_article_with_its_owner(testcase):
owner = create_user()
testcase.owner = owner
unpublished = create_unpublished_article(commit=False)
unpublished.owner = owner
unpublished.save()
return {'pk': unpublished.pk}
def get_owner_credentials(testcase):
return {
'username': testcase.user.username,
'password': '1234' # User contains hashed password only
'username': testcase.owner.username,
'password': '1234' # User contains hashed password only
}
class YourSmokeTests(SmokeTestCase):
class UnpublishedArticleSmokeTestCase(SmokeTestCase):
TESTS_CONFIGURATION = (
('url', 200, 'GET',
{'url_kwargs': create_object,
'user_credentials': get_user_credentials}),
('articles:article', 404, 'GET',
{'url_kwargs': create_article_without_owner,
'comment': 'Anonymous access to unpublished article.'}), # 1
('articles:article', 404, 'GET',
{'url_kwargs': create_article_without_owner,
'user_credentials': create_and_return_user_credentials,
'comment': 'Some user access to unpublished article.'}), # 2
('articles:article', 200, 'GET',
{'url_kwargs': create_article_with_its_owner,
'user_credentials': get_owner_credentials,
'comment': 'Owner access to unpublished article.'}), # 3
)
License
-------

MIT
26 changes: 26 additions & 0 deletions example_project/articles/migrations/0002_auto_20151009_1404.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('articles', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='article',
name='owner',
field=models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AddField(
model_name='article',
name='published',
field=models.BooleanField(default=True),
),
]
3 changes: 3 additions & 0 deletions example_project/articles/models.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

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


class Article(models.Model):
headline = models.CharField(max_length=150)
description = models.TextField(blank=True)
published = models.BooleanField(default=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True)

def __unicode__(self):
return self.headline
Expand Down
3 changes: 0 additions & 3 deletions example_project/articles/tests.py

This file was deleted.

10 changes: 9 additions & 1 deletion example_project/articles/views.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@

from django.http import Http404
from django.views.generic import ListView, DetailView, CreateView

from .models import Article


class ArticlesView(ListView):
model = Article
template_name = 'articles.html'
context_object_name = 'articles'
queryset = Article.objects.filter(published=True)


class ArticleDetailView(DetailView):
model = Article
template_name = 'article.html'

def get_object(self, queryset=None):
article = super(ArticleDetailView, self).get_object(queryset)
if not article.published and article.owner != self.request.user:
raise Http404()
return article


class ArticleCreateView(CreateView):
model = Article
Expand Down
14 changes: 0 additions & 14 deletions example_project/example_project/tests.py

This file was deleted.

2 changes: 1 addition & 1 deletion example_project/example_project/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

urlpatterns = [
url(r'^admin/', include(admin.site.urls)),
url(r'^$', TemplateView.as_view(template_name="base.html")),
url(r'^$', TemplateView.as_view(template_name="base.html"), name='home'),
url(r'^login/$', login, {'template_name': 'login.html'}, name='login'),
url(r'^logout/$', logout, {'template_name': 'logout.html'}, name='logout'),
url(r'^is_authenticated/$', IsAuthenticated.as_view(),
Expand Down

0 comments on commit f4fdb3c

Please sign in to comment.