From 76e0d405e059c91a1551d7f6b6012daba5a59ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Zaj=C4=85c?= Date: Tue, 3 Jul 2018 14:35:07 +0200 Subject: [PATCH] Some unittest created and pep8 --- README.md | 8 ++ requirements.txt | 2 + storage/admin.py | 10 +- storage/apiviews.py | 3 +- storage/factories.py | 65 ++++++++++++ storage/management/commands/importbooks.py | 3 +- storage/serializers.py | 2 + storage/tests.py | 111 ++++++++++++++++++++- storage/urls.py | 4 +- storage/widgets.py | 5 +- 10 files changed, 200 insertions(+), 13 deletions(-) create mode 100644 storage/factories.py diff --git a/README.md b/README.md index 3d82986..cc547f4 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,14 @@ docker-compose up docker-compose build ``` +### Tests + +Before test run containers. See "Build & run". + +```sh +docker-compose exec web python manage.py test --noinput +``` + ### Troubleshooting - https://askubuntu.com/q/615394/413683 diff --git a/requirements.txt b/requirements.txt index 87bac65..83a4c6d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,3 +14,5 @@ pyldap==2.4.28 requests==2.16.5 urllib3==1.21.1 django_markdown2==0.3.0 +factory-boy==2.11.1 +Faker==0.8.16 diff --git a/storage/admin.py b/storage/admin.py index 13c297a..570a07d 100644 --- a/storage/admin.py +++ b/storage/admin.py @@ -1,7 +1,8 @@ from django import forms from django.contrib import admin +from django.contrib.auth.models import Group, User -from django_select2.forms import ModelSelect2Widget, Select2MultipleWidget +from django_select2.forms import Select2MultipleWidget from .models import Item, ItemImage, Category, Label from .widgets import ItemSelectWidget, PropsSelectWidget @@ -36,7 +37,8 @@ class ItemAdmin(admin.ModelAdmin): inlines = [ItemImageInline, LabelInline] save_on_top = True - def _name(self, obj): + @classmethod + def _name(cls, obj): return '-' * obj.get_level() + '> ' + obj.name def save_model(self, request, obj, form, change): @@ -72,9 +74,5 @@ class ItemAdmin(admin.ModelAdmin): admin.site.register(Item, ItemAdmin) admin.site.register(Category) - -from django.contrib.auth.models import User -from django.contrib.auth.models import Group - admin.site.unregister(User) admin.site.unregister(Group) diff --git a/storage/apiviews.py b/storage/apiviews.py index a043542..47d60ab 100644 --- a/storage/apiviews.py +++ b/storage/apiviews.py @@ -1,4 +1,4 @@ -from rest_framework import viewsets, generics, filters +from rest_framework import viewsets, filters from rest_framework.response import Response from rest_framework.decorators import detail_route from rest_framework.permissions import AllowAny @@ -46,7 +46,6 @@ class ItemViewSet(viewsets.ModelViewSet): filter_backends = (SmartSearchFilterBackend, filters.OrderingFilter) ordering_fields = '__all__' - def get_queryset(self): return Item.get_roots() diff --git a/storage/factories.py b/storage/factories.py new file mode 100644 index 0000000..94e43fb --- /dev/null +++ b/storage/factories.py @@ -0,0 +1,65 @@ +from factory import LazyAttribute, SubFactory +from factory.django import DjangoModelFactory +from faker import Faker +from random import randint +from tree.fields import Path + +from django.contrib.auth.models import User + +from .models import Category, Item, ItemImage, Label, STATES + +fake = Faker('pl_PL') + + +class UserFactory(DjangoModelFactory): + """ + Creates and returns instance of User model + """ + username = LazyAttribute(lambda n: '{}{}'.format(fake.user_name(), randint(0, 100000))) + + class Meta: + model = User + + +class CategoryFactory(DjangoModelFactory): + """ + Creates and returns instance of Category + """ + name = 'elektronika' + icon_id = 'elka' + + class Meta: + model = Category + + +class ItemFactory(DjangoModelFactory): + """ + Creates and returns instance of Item + """ + path = Path(field='field1', value='path1') + name = 'śrubokręt' + description = 'czerwony śrubokręt krzyżakowy' + state = STATES[0][0] + + class Meta: + model = Item + + +class ItemImageFactory(DjangoModelFactory): + """ + Creates and returns instance of ItemImage and creates related Item + """ + item = SubFactory(ItemFactory) + + class Meta: + model = ItemImage + + +class LabelFactory(DjangoModelFactory): + """ + Creates and returns instance of Label and creates related Item + """ + item = SubFactory(ItemFactory) + + class Meta: + model = Label diff --git a/storage/management/commands/importbooks.py b/storage/management/commands/importbooks.py index 66d2f5b..db26658 100644 --- a/storage/management/commands/importbooks.py +++ b/storage/management/commands/importbooks.py @@ -1,8 +1,9 @@ -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from storage.models import Item from io import StringIO import csv + class Command(BaseCommand): help = 'Imports book library from specified wiki page dump' diff --git a/storage/serializers.py b/storage/serializers.py index f7f58a8..551dd71 100644 --- a/storage/serializers.py +++ b/storage/serializers.py @@ -8,9 +8,11 @@ class ItemSerializer(HStoreSerializer): model = Item fields = ('uuid', 'name', 'description', 'props', 'state', 'parent') + class LabelSerializer(serializers.ModelSerializer): item = ItemSerializer(required=False) item_id = serializers.PrimaryKeyRelatedField(queryset=Item.objects, source='item') + class Meta: model = Label fields = ('id', 'item', 'item_id', 'style') diff --git a/storage/tests.py b/storage/tests.py index 7ce503c..9b91eb5 100644 --- a/storage/tests.py +++ b/storage/tests.py @@ -1,3 +1,112 @@ +from django.contrib.auth.models import User +from django.shortcuts import reverse from django.test import TestCase -# Create your tests here. +from .factories import CategoryFactory, ItemFactory, ItemImageFactory, LabelFactory, UserFactory +from .models import Category, Item, ItemImage, Label + + +class ModelsTestCase(TestCase): + """ + Test factories and models + """ + def test_user_factory(self): + """ + Test user creation + """ + u1 = UserFactory() + u2 = UserFactory(email='kowalski@example.com') + + self.assertIsInstance(u1, User) + self.assertIsInstance(u2, User) + + def test_category_factory(self): + """ + test category creation + """ + c = CategoryFactory() + + self.assertIsInstance(c, Category) + + def test_category_model(self): + """ + create category instance + """ + c = CategoryFactory( + name='Elektronika', + icon_id='elektronika-icon-id', + ) + self.assertIsInstance(c, Category) + + # TODO: create tests for Item and ItemImage and Label models + # TODO: create tests for parent items + + def test_item_factory(self): + """ + test item creation + """ + i = ItemFactory() + + self.assertIsInstance(i, Item) + + def test_item_image_factory(self): + """ + test item creation + """ + ii = ItemImageFactory() + + self.assertIsInstance(ii, ItemImage) + + def test_get_or_create_label(self): + """ + test get_or_create_label method + """ + i = ItemFactory() + + obj = i.get_or_create_label() + + self.assertIsInstance(obj, Label) + + def test_label_factory(self): + """ + test label creation + """ + label = LabelFactory() + + self.assertIsInstance(label, Label) + + +class ViewsTestCase(TestCase): + def setUp(self): + """ + Create some models + """ + c = CategoryFactory( + name='Elektronika', + icon_id='elektronika-icon-id', + ) + i = ItemFactory(name='butelka') + i.categories.add(c) + + i = ItemFactory(name='nakrętka') + i.categories.add(c) + + def test_search_view(self): + """ + test search with query + """ + url = reverse('item-search') + self.assertEqual('/search', url) + + response = self.client.get(url) + + self.assertEqual(200, response.status_code) + self.assertTemplateUsed(response, 'results.html') + + # Additional, try to check some content + self.assertEqual(2, len(response.context[0]['results'])) + for item in response.context[0]['results']: + self.assertIsInstance(item, Item) + + # TODO: create tests for other views + # TODO: test searching items diff --git a/storage/urls.py b/storage/urls.py index fce08cb..4a25657 100644 --- a/storage/urls.py +++ b/storage/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import include, url +from django.conf.urls import url from storage.views import ( index, search, item_display, label_lookup, ItemSelectView, PropSelectView ) urlpatterns = [ url(r'^$', index), - url(r'^search$', search), + url(r'^search$', search, name='item-search'), url(r'^item/(?P.*)$', item_display, name='item-display'), url(r'^autocomplete.json$', ItemSelectView.as_view(), name='item-complete'), url(r'^autocomplete_prop.json$', PropSelectView.as_view(), name='prop-complete'), diff --git a/storage/widgets.py b/storage/widgets.py index 8c254d6..af84f57 100644 --- a/storage/widgets.py +++ b/storage/widgets.py @@ -31,7 +31,10 @@ class PropsSelectWidget(DictionaryFieldWidget): attrs = {} # it's called "original" because it will be replaced by a copy attrs['class'] = 'hstore-original-textarea' - w = HeavySelect2Widget(data_view='prop-complete', attrs={'data-tags': 'true', 'class': 'hs-key'}) + w = HeavySelect2Widget( + data_view='prop-complete', + attrs={'data-tags': 'true', 'class': 'hs-key'}, + ) # get default HTML from AdminTextareaWidget html = AdminTextareaWidget.render(self, name, value, attrs)