Skip to content
Snippets Groups Projects
Commit 397c9687 authored by borzechof99's avatar borzechof99 :whale2:
Browse files

Merge branch '32-fill-database-with-test-data' into 'master'

Resolve "Write a Script to fill the Database with Test data"

Closes #32

See merge request swp-unisport/team-warumkeinrust/unisport-o-mat!39
parents 30f4a476 311d17a5
No related branches found
No related tags found
No related merge requests found
Showing
with 325 additions and 3 deletions
#SOURCE: https://www.codingforentrepreneurs.com/blog/django-virtualenv-python-gitignore-file/
# Project related
/media
/unisportomat/media/*
# Virtualenv related
bin/
......
......@@ -70,3 +70,19 @@ python manage.py runserver
```
If successful, you can now see the running server in your browser at `http://127.0.0.1:8000`.
## Populate the database with test data
To populate the database with some test data run
```
python manage.py seed_db [-y] [--seed SEED] [--no-superuser]
```
All the existing data from your database will be lost!
Per default a super user called "admin" will be created for development.
You will be prompted for a password.
Run `python manage.py seed_db --help` for more information.
## Use the django admin interface to view and edit data during development
If you started the server as described above, you can access the django admin interface on
[localhost:8000/admin](localhost:8000/admin).
If you seeded the database you can login with username: "admin" and the password you specified.
......@@ -3,8 +3,18 @@
from django.contrib import admin
# Register your models here.
from .models import Sport, Criterion, CriterionRating
from .models import (
Sport,
Question,
Criterion,
CriterionRating,
CallToMove,
KnowledgeSnack,
)
admin.site.register(Sport)
admin.site.register(Criterion)
admin.site.register(Question)
admin.site.register(CriterionRating)
admin.site.register(CallToMove)
admin.site.register(KnowledgeSnack)
[
{
"model": "quiz.calltomove",
"pk": 1,
"fields": {
"text": "Kreise deine Arme vor der nächsten Frage 3x nach hinten",
"image": "test_image.png"
}
}
]
\ No newline at end of file
[
{
"model": "quiz.criterion",
"pk": 1,
"fields": {
"name": "Outdoorsport"
}
}
]
\ No newline at end of file
[
{
"model": "quiz.criterionrating",
"pk": 1,
"fields": {
"rating": 1,
"criterion": 1,
"sport": 1
}
}
]
\ No newline at end of file
unisportomat/quiz/fixtures/images/logo.png

18.3 KiB

[
{
"model": "quiz.knowledgesnack",
"pk": 1,
"fields": {
"text": "Dass Treppensteigen fast 5x so viele Kalorien verbrennt, als die Nutzung des Aufzuges?",
"image": "logo.png"
}
}
]
\ No newline at end of file
[
{
"model": "quiz.question",
"pk": 1,
"fields": {
"text": "Ich mache am liebsten draußen Sport"
}
}
]
\ No newline at end of file
[
{
"model": "quiz.sport",
"pk": 1,
"fields": {
"name": "Jiu Jitsu",
"url": "http://www.test.de"
}
}
]
\ No newline at end of file
[{"model": "auth.user", "pk": 1, "fields": {"password": "pbkdf2_sha256$260000$75I180x9FwfD0xuW3TGMU4$B1mg2ywC0kSYkbkmFuSyCq8/yxD9nnU7TNq7VmJsnFs=", "last_login": "2021-06-06T07:41:10.617Z", "is_superuser": true, "username": "admin", "first_name": "", "last_name": "", "email": "", "is_staff": true, "is_active": true, "date_joined": "2021-06-05T15:02:57.005Z", "groups": [], "user_permissions": []}}]
\ No newline at end of file
"""
Seeds the database with test data.
You can call this by python manage.py seed_db
"""
import random
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.core.management.base import BaseCommand
from quiz.models import (
Sport,
Criterion,
Question,
CallToMove,
KnowledgeSnack,
)
class Command(BaseCommand):
"""
Seeds the database with test data.
You can call this by python manage.py seed_db
"""
help = "Seeds the database with test data"
def add_arguments(self, parser):
"""
Add arguments to command that can be added to the command in command line
In this case there's only one arg that you can call by
python manage.py seed_db --yes
"""
parser.add_argument(
"-y",
"--yes",
action="store_true",
help="Don't ask to confirm database flushing",
)
parser.add_argument(
"--seed",
type=int,
default=42,
help="Optional seed for random generator. Defaults to 42",
)
parser.add_argument(
"--no-superuser",
action="store_true",
help="No super user shall be created",
)
def handle(self, *args, **options):
"""Create some objects for all models"""
# delete all present database entries (necessary because of unique constraints)
call_command("flush", "--no-input" if options["yes"] else [])
# Create admin user for using django admin interface during development
if not options["no_superuser"]:
self.stdout.write("\nSpecify admin password for development:")
call_command("createsuperuser", "--username=admin", "--email=''")
# Seed random generator to make this script deterministic
random.seed(options["seed"])
# Create sports
sports_names = [
"After Work Fitness",
"Ballett",
"Basketball",
"Beachvolleyball",
"Bouldern",
]
for name in sports_names:
Sport(name=name).save()
# Create criteria
criteria_names = [
"Einzelsport",
"Mannschaftssport",
"Ausdauer",
"Kraft",
"Kampfsport",
]
for name in criteria_names:
Criterion(name=name).save()
# Create ratings for all sports and criterions
for sport in Sport.objects.all():
for criterion in Criterion.objects.all():
sport.rate(criterion, random.randint(1, 10))
# Create questions
questions = [
"Ich würde am liebsten gemeinsam mit anderen trainieren.",
"Teamgeist und Wir-Gefühl sind für mich beim Sport eine große Motivation.",
"Ich betreibe lieber alleine Sport.",
"Ich bin bereit, mir ggf. Material für die Sportart zu kaufen.",
"Ich bevorzuge das Sportangebot draußen in der Natur vor dem Indoor-Angebot.",
]
for number, criterion in enumerate(Criterion.objects.all()):
Question(text=questions[number], criterion=criterion).save()
# Create Calls to Move
calls_to_move = [
"Kreise deine Schultern vor der nächsten Frage 3x nach hinten",
"Stehe auf, beuge dich mit gestrecktem Rücken nach vorne und greife deinen Stuhl.",
"Mache vor der nächsten Frage 3 Jumping Jacks",
]
image = SimpleUploadedFile(
name="test_image.png",
content=open("quiz/fixtures/images/test_image.png", "rb").read(),
content_type="image/png",
)
for text in calls_to_move:
CallToMove(text=text, image=image).save()
# Create Knowledge Snacks
knowledge_snacks = [
"Dass Treppensteigen fast 5x so viele Kalorien verbrennt, wie das Nutzen des Aufzuges?",
"Dass das Spielemobil zur Mittagszeit immer auf dem Campus unterwegs ist?",
"Dass regelmäßige Bewegung Herz-Kreislauf-Erkrankungen vorbeugt?",
]
image = SimpleUploadedFile(
name="logo.png",
content=open("quiz/fixtures/images/logo.png", "rb").read(),
content_type="image/png",
)
for text in knowledge_snacks:
KnowledgeSnack(text=text, image=image).save()
......@@ -17,6 +17,9 @@ class CriterionRating(models.Model):
criterion = models.ForeignKey("Criterion", on_delete=models.CASCADE)
sport = models.ForeignKey("Sport", on_delete=models.CASCADE)
def __str__(self):
return str(self.sport) + " - " + str(self.criterion) + ": " + str(self.rating)
class Sport(models.Model):
"""
......@@ -55,6 +58,9 @@ class Criterion(models.Model):
name = models.TextField()
def __str__(self):
return self.name
class CallToMove(models.Model):
"""Defines text and image that are used to show a call to move between questions"""
......@@ -62,6 +68,9 @@ class CallToMove(models.Model):
text = models.TextField()
image = models.ImageField(null=True, max_length=200)
def __str__(self):
return self.text
class KnowledgeSnack(models.Model):
"""Defines text and image that are used to show a KnowledgeSnack between questions"""
......@@ -69,6 +78,9 @@ class KnowledgeSnack(models.Model):
text = models.TextField()
image = models.ImageField(null=True, max_length=200)
def __str__(self):
return self.text
class Question(models.Model):
"""Defines a Question that is assigned to exactly one Criterion"""
......@@ -77,3 +89,6 @@ class Question(models.Model):
criterion = models.OneToOneField(
Criterion, on_delete=models.CASCADE, primary_key=True
)
def __str__(self):
return self.text
......@@ -5,9 +5,17 @@ import shutil
import tempfile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.management import call_command
from django.test import TestCase, override_settings
from django.conf import settings
from .models import Sport, Criterion, CallToMove, KnowledgeSnack, Question
from .models import (
Sport,
Criterion,
CriterionRating,
CallToMove,
KnowledgeSnack,
Question,
)
class SportModelTest(TestCase):
......@@ -188,3 +196,83 @@ class CriterionAndQuestionModelTest(TestCase):
Question(text=text, criterion=self.criterion).save()
test_question = Question.objects.first()
self.assertEqual(test_question.text, text)
class FixturesTest(TestCase):
"""
These are the tests for the fixtures in quiz/fixtures.
Fixtures can be used to populate the database with test data.
They can be used in automated tests, but also in development.
"""
fixtures = [
"sports.json",
"criteria.json",
"criterion_ratings.json",
"questions.json",
"calls_to_move.json",
"knowledge_snacks.json",
]
def test_sports_created_by_fixture(self):
"""If the sports fixture is loaded there exists a sport with the given data."""
sport = Sport.objects.get(pk=1)
self.assertEqual(sport.name, "Jiu Jitsu")
self.assertEqual(sport.url, "http://www.test.de")
def test_criterion_created_by_fixture(self):
"""If the criteria fixture is loaded there exists a criterion with the given data"""
criterion = Criterion.objects.get(pk=1)
self.assertEqual(criterion.name, "Outdoorsport")
def test_criterion_rating_created_by_fixture(self):
"""If the criterion_ratings fixture is loaded the given sport has a corresponding rating"""
criterion = Criterion.objects.get(name="Outdoorsport")
sport = Sport.objects.get(name="Jiu Jitsu")
self.assertEqual(sport.get_rating(criterion), 1)
def test_question_created_by_fixture(self):
"""If the questions fixture is loaded there exists a question with the given data"""
question = Question.objects.get(pk=1)
criterion = Criterion.objects.get(name="Outdoorsport")
self.assertEqual(question.text, "Ich mache am liebsten draußen Sport")
self.assertEqual(question.criterion, criterion)
def test_call_to_move_created_by_fixture(self):
"""If the call to move fixture is loaded there exists a call to move with the given data"""
call_to_move = CallToMove.objects.get(pk=1)
self.assertEqual(
call_to_move.text, "Kreise deine Arme vor der nächsten Frage 3x nach hinten"
)
self.assertEqual(call_to_move.image.name, "test_image.png")
def test_knowledge_snack_created_by_fixture(self):
"""
If the knowledge snack fixture is loaded there exists a knowledge snack with the given data
"""
knowledge_snack = KnowledgeSnack.objects.get(pk=1)
self.assertEqual(
knowledge_snack.text,
"Dass Treppensteigen fast 5x so viele Kalorien verbrennt, "
"als die Nutzung des Aufzuges?",
)
self.assertEqual(knowledge_snack.image.name, "logo.png")
class SeedingTest(TestCase):
"""Tests the seed_db command in quiz/management/commands"""
def test_seed_with_complete_data(self):
"""If seed_db is called then there exists a certain number of elements per model"""
# call the seed command without asking for confirmation
call_command("seed_db", ["--yes", "--no-superuser"])
n_sports = 5
n_criteria = 5
self.assertEqual(Sport.objects.count(), n_sports)
self.assertEqual(Criterion.objects.count(), n_criteria)
self.assertEqual(CriterionRating.objects.count(), n_sports * n_criteria)
self.assertEqual(Question.objects.count(), n_criteria)
self.assertEqual(CallToMove.objects.count(), 3)
self.assertEqual(KnowledgeSnack.objects.count(), 3)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment