Suche…


Testen - ein vollständiges Beispiel

Dies setzt voraus, dass Sie die Dokumentation zum Starten eines neuen Django-Projekts gelesen haben. Nehmen wir an, die Haupt-App in Ihrem Projekt heißt td (kurz für testgetrieben). Um Ihren ersten Test zu erstellen, erstellen Sie eine Datei mit dem Namen test_view.py und fügen Sie den folgenden Inhalt ein.

from django.test import Client, TestCase

class ViewTest(TestCase):

    def test_hello(self):
        c = Client()
        resp = c.get('/hello/')
        self.assertEqual(resp.status_code, 200)

Sie können diesen Test mit durchführen

 ./manage.py test

und es wird am natürlichsten scheitern! Es wird ein Fehler ähnlich dem folgenden angezeigt.

Traceback (most recent call last):
  File "/home/me/workspace/td/tests_view.py", line 9, in test_hello
    self.assertEqual(resp.status_code, 200)
AssertionError: 200 != 404

Warum passiert das? Weil wir noch keine Sicht dafür definiert haben! Also machen wir's. Erstellen Sie eine Datei mit dem Namen views.py, und fügen Sie den folgenden Code ein

from django.http import HttpResponse
def hello(request):
    return HttpResponse('hello')

Als nächstes ordnen Sie es dem / hello / durch Bearbeiten der URLs py wie folgt zu:

from td import views

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^hello/', views.hello),
    ....
]

Führen Sie den Test jetzt erneut aus ./manage.py test erneut und Viola !!

Creating test database for alias 'default'...
.
----------------------------------------------------------------------
Ran 1 test in 0.004s

OK

Django-Modelle effektiv testen

Eine Klasse annehmen

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=50)
   
    def __str__(self):
        return self.name
    
    def get_absolute_url(self):
        return reverse('view_author', args=[str(self.id)])


class Book(models.Model):
    author = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    private = models.BooleanField(default=false)
    publish_date = models.DateField()

    def get_absolute_url(self):
        return reverse('view_book', args=[str(self.id)])
    
    def __str__(self):
        return self.name

Testbeispiele

from django.test import TestCase
from .models import Book, Author

class BaseModelTestCase(TestCase):

    @classmethod
    def setUpClass(cls):
        super(BaseModelTestCase, cls).setUpClass()
        cls.author = Author(name='hawking')
        cls.author.save()
        cls.first_book = Book(author=cls.author, name="short_history_of_time")
        cls.first_book.save()
        cls.second_book = Book(author=cls.author, name="long_history_of_time")
        cls.second_book.save()


class AuthorModelTestCase(BaseModelTestCase):
    def test_created_properly(self):
         self.assertEqual(self.author.name, 'hawking')
         self.assertEqual(True, self.first_book in self.author.book_set.all())
    
    def test_absolute_url(self):
        self.assertEqual(self.author.get_absolute_url(), reverse('view_author', args=[str(self.author.id)]))

class BookModelTestCase(BaseModelTestCase):
    
    def test_created_properly(self:
        ...
        self.assertEqual(1, len(Book.objects.filter(name__startswith='long'))
    
    def test_absolute_url(self):
        ...

Ein paar Punkte

  • created_properly Tests werden verwendet, um die Zustandseigenschaften von Django-Modellen zu überprüfen. Sie helfen dabei, Sicherheitsmaßnahmen zu treffen, wenn wir Standardwerte, file_upload_paths usw. geändert haben.
  • absolute_url mag trivial erscheinen, aber ich habe festgestellt, dass es mir dabei geholfen hat, einige Fehler beim Ändern von URL-Pfaden zu vermeiden
  • Ebenso schreibe ich Testfälle für alle innerhalb eines Modells implementierten Methoden (unter Verwendung von mock Objekten usw.).
  • Durch die Definition eines gemeinsamen BaseModelTestCase wir die notwendigen Beziehungen zwischen den Modellen BaseModelTestCase , um ein ordnungsgemäßes Testen sicherzustellen.

Wenn Sie Zweifel haben, schreiben Sie einen Test. Triviale Verhaltensänderungen werden durch die Aufmerksamkeit für Details aufgefangen und lange vergessene Teile des Codes verursachen keine unnötigen Probleme.

Zugriffssteuerung in Django-Ansichten testen

tl; dr : Erstellen Sie eine Basisklasse, die zwei Benutzerobjekte definiert (z. B. user und another_user ). Erstellen Sie Ihre anderen Modelle und definieren Sie drei Client Instanzen.

  • self.client : In Browser angemeldeter user
  • self.another_client : Repräsentant eines anderen another_user
  • self.unlogged_client : Repräsentation einer nicht angemeldeten Person

Greifen Sie jetzt auf alle Ihre öffentlichen und privaten URLs von diesen drei Clientobjekten zu und richten Sie die erwartete Antwort ein. Im Folgenden habe ich die Strategie für ein Book Objekt vorgestellt, das entweder private (im Besitz einiger privilegierter Benutzer) oder public (für jeden sichtbar) sein kann.

from django.test import TestCase, RequestFactory, Client
from django.core.urlresolvers import reverse

class BaseViewTestCase(TestCase):

    @classmethod
    def setUpClass(cls):
        super(BaseViewTestCase, cls).setUpClass()
        cls.client = Client()
        cls.another_client = Client()
        cls.unlogged_client = Client()
        cls.user = User.objects.create_user(
                'dummy',password='dummy'
                )
        cls.user.save()
        cls.another_user = User.objects.create_user(
                'dummy2', password='dummy2'
                )
        cls.another_user.save()
        cls.first_book = Book.objects.create(
                name='first',
                private = true
        )
        cls.first_book.readers.add(cls.user)
        cls.first_book.save()
        cls.public_book = Template.objects.create(
                name='public',
                private=False
        )
        cls.public_book.save()


    def setUp(self):
        self.client.login(username=self.user.username, password=self.user.username)
        self.another_client.login(username=self.another_user.username, password=self.another_user.username)


"""
   Only cls.user owns the first_book and thus only he should be able to see it.
   Others get 403(Forbidden) error
"""
class PrivateBookAccessTestCase(BaseViewTestCase):
    
    def setUp(self):
        super(PrivateBookAccessTestCase, self).setUp()
        self.url = reverse('view_book',kwargs={'book_id':str(self.first_book.id)})

    def test_user_sees_own_book(self):
        response = self.client.get(self.url)
        self.assertEqual(200, response.status_code)
        self.assertEqual(self.first_book.name,response.context['book'].name)
        self.assertTemplateUsed('myapp/book/view_template.html')

    def test_user_cant_see_others_books(self):
        response = self.another_client.get(self.url)
        self.assertEqual(403, response.status_code)
        
    def test_unlogged_user_cant_see_private_books(self):
        response = self.unlogged_client.get(self.url)
        self.assertEqual(403, response.status_code)

"""
    Since book is public all three clients should be able to see the book
"""
 class PublicBookAccessTestCase(BaseViewTestCase):
    
    def setUp(self):
        super(PublicBookAccessTestCase, self).setUp()
        self.url = reverse('view_book',kwargs={'book_id':str(self.public_book.id)})

    def test_user_sees_book(self):
        response = self.client.get(self.url)
        self.assertEqual(200, response.status_code)
        self.assertEqual(self.public_book.name,response.context['book'].name)
        self.assertTemplateUsed('myapp/book/view_template.html')

    def test_another_user_sees_public_books(self):
        response = self.another_client.get(self.url)
        self.assertEqual(200, response.status_code)
        
    def test_unlogged_user_sees_public_books(self):
        response = self.unlogged_client.get(self.url)
        self.assertEqual(200, response.status_code)

Die Datenbank und das Testen

Django verwendet beim Testen spezielle Datenbankeinstellungen, sodass Tests die Datenbank normalerweise verwenden können, aber standardmäßig in einer leeren Datenbank ausgeführt werden. Datenbankänderungen in einem Test werden von einem anderen nicht erkannt. Zum Beispiel werden die beiden folgenden Tests bestanden:

from django.test import TestCase
from myapp.models import Thing

class MyTest(TestCase):

    def test_1(self):
        self.assertEqual(Thing.objects.count(), 0)
        Thing.objects.create()
        self.assertEqual(Thing.objects.count(), 1)

    def test_2(self):
        self.assertEqual(Thing.objects.count(), 0)
        Thing.objects.create(attr1="value")
        self.assertEqual(Thing.objects.count(), 1)

Fixtures

Wenn Sie Datenbankobjekte für mehrere Tests verwenden möchten, erstellen Sie sie entweder in der setUp Methode des Testfalls. Wenn Sie in Ihrem Django-Projekt Fixtures definiert haben, können diese zusätzlich so eingefügt werden:

class MyTest(TestCase):
    fixtures = ["fixture1.json", "fixture2.json"]

Standardmäßig sucht Django in jeder App nach Fixtures im fixtures Verzeichnis. Weitere Verzeichnisse können mit der Einstellung FIXTURE_DIRS gesetzt werden:

# myapp/settings.py
FIXTURE_DIRS = [
    os.path.join(BASE_DIR, 'path', 'to', 'directory'),
]

Angenommen, Sie haben ein Modell wie folgt erstellt:

# models.py
from django.db import models


class Person(models.Model):
    """A person defined by his/her first- and lastname."""
    firstname = models.CharField(max_length=255)
    lastname = models.CharField(max_length=255)

Dann könnten Ihre .json-Fixtures so aussehen:

# fixture1.json
[
    { "model": "myapp.person",
        "pk": 1,
        "fields": {
            "firstname": "Peter",
            "lastname": "Griffin"
        }
    },
    { "model": "myapp.person",
        "pk": 2,
        "fields": {
            "firstname": "Louis",
            "lastname": "Griffin"
        }
    },
]

Verwenden Sie die Testdatenbank erneut

Um Ihre Testläufe zu beschleunigen, können Sie dem Verwaltungsbefehl mitteilen, die Testdatenbank erneut zu verwenden (und zu verhindern, dass sie vor jedem Testlauf erstellt und gelöscht wird). Dies kann mit dem keepdb-Flag (oder der Abkürzung -k ) wie folgt durchgeführt werden:

# Reuse the test-database (since django version 1.8)
$ python manage.py test --keepdb

Begrenzen Sie die Anzahl der durchgeführten Tests

Es ist möglich, die von manage.py test ausgeführten Tests manage.py test indem Sie manage.py test , welche Module vom manage.py test sollen:

# Run only tests for the app names "app1"
$ python manage.py test app1

# If you split the tests file into a module with several tests files for an app
$ python manage.py test app1.tests.test_models

# it's possible to dig down to individual test methods.
$ python manage.py test app1.tests.test_models.MyTestCase.test_something

Wenn Sie eine Reihe von Tests durchführen möchten, können Sie ein Muster von Dateinamen übergeben. Beispielsweise möchten Sie möglicherweise nur Tests ausführen, die Ihre Modelle betreffen:

$ python manage.py test -p test_models*
Creating test database for alias 'default'...
.................................................
----------------------------------------------------------------------
Ran 115 tests in 3.869s

OK

Schließlich ist es möglich, die Testsuite beim ersten Fehler mithilfe von --failfast . Dieses Argument ermöglicht es, den potenziellen Fehler in der Suite schnell zu ermitteln:

$ python manage.py test app1
...F..
----------------------------------------------------------------------
Ran 6 tests in 0.977s

FAILED (failures=1)


$ python manage.py test app1 --failfast
...F
======================================================================
[Traceback of the failing test]
----------------------------------------------------------------------
Ran 4 tests in 0.372s

FAILED (failures=1)


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow