Fakultas Ilmu Komputer UI

Commit c0181673 authored by Muhammad Ilham Peruzzi's avatar Muhammad Ilham Peruzzi
Browse files

Merge branch 'testinggoat/ch6' into 'master'

Testinggoat/ch6

See merge request !4
parents 43a4b86e 3a6d30d6
Pipeline #21278 passed with stages
in 5 minutes and 41 seconds
......@@ -12,7 +12,7 @@ Test:
script:
- python3 manage.py makemigrations
- python3 manage.py migrate
- python3 manage.py test
- python3 manage.py test lists
tags:
- test
......@@ -43,7 +43,6 @@ TestFunctional:
- apt-get install -y xvfb
- wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip
- python manage.py runserver 8000 &
when: on_success
script:
- python3 functional_tests_chrome.py
\ No newline at end of file
- python3 manage.py test functional_tests
\ No newline at end of file
......@@ -2,3 +2,42 @@
Muhammad Ilham Peruzzi - 1606823475 - Computer Science 2016 - PMPL A - Practice Repo
Link Heroku : https://pmpl-peruzzi.herokuapp.com/
# Cerita Exercise 3
## Isolating testing dalam Exercise 3
Dalam Lab 3 ini, test isolation dilakukan dengan memisahkan unittest dan functional test. Pada Lab sebelumnya, functional test merupakan test yang bersifat
independen dan kita harus menjalankan test tersebut secara manual. Agar unittest dan functional test dapat diautomisasi, kita harus merubah penamaan
functional_test.py menjadi test.py saja, dikarenakan test runner hanya membaca file dengan awalan test.
Untuk membuat struktur project lebih rapi, functional test yang sudah diubah namanya menjadi test.py disimpan pada direktori terpisah, bernama functional_test.
Jadi, saat kita menjalankan perintah:
```bash
python manage.py test
```
maka unittest dan functional_test akan dijalankan secara otomatis. Untuk memisahkan menjalankan test tersebut, kita bisa menggunakan perintah terpisah.
Untuk menjalankan unittest saja, bisa menggunakan perintah:
```bash
python manage.py test <nama-app>
```
Sedangkan untuk menjalankan functional test saja, bisa menggunakan perintah:
```bash
python manage.py test <folder-functional-test>
```
Selain itu, isolation test juga dilakukan dengan memisahkan server untuk melakukan functional test dengan menggunakan LiveServerTestCase.
Class tersebut akan membuat sebuah database test otomatis yang terpisah dengan database yang kita gunakan, lalu membuat development server sendiri untuk
melakukan functional testing, sehingga hasil dari functional test yang dijalankan tidak memperngaruhi aplikasi yang sedang berjalan.
Dengan demikian kita telah berhasil melakukan test isolation.
## Perbedaan Antara Design Baru dan Design Sebelumnya
- Pada desain yang baru menggunakan class LiveServerTestCase, sehingga saat menjalankan functional test tidak perlu menggunakan env heroku (baik server maupun database)
- Pada desain yang baru functional test dapat dijalankan secara otomatis dengan menggunakan perintah yang telah disebutkan diatas
## Catatan
Pada Lab 3 ini, karena saya menggunakan textbook yang berbeda dengan yang ada pada ebook di website, maka secara tidak sadar mungkin saya sudah mengerjakan
tugas untuk Lab selanjutnya, sehingga pada Lab ini saya sudah mencapai chapter 7 (https://www.obeythetestinggoat.com/book/chapter_working_incrementally.html)
\ No newline at end of file
......@@ -5,18 +5,10 @@ from selenium.webdriver.common.keys import Keys
import time
import unittest
import environ
from django.test import LiveServerTestCase
root = environ.Path(__file__)
env = environ.Env(DEBUG=(bool, False), )
environ.Env.read_env('.env')
HEROKU_APP_HOST = env("HEROKU_APP_HOST")
print("HEROKU_APP_HOST is", HEROKU_APP_HOST)
MAX_WAIT = 5
class NewVisitorTest(unittest.TestCase):
class NewVisitorTest(LiveServerTestCase):
def setUp(self):
chrome_options = Options()
......@@ -33,8 +25,13 @@ class NewVisitorTest(unittest.TestCase):
def tearDown(self):
self.browser.quit()
def check_for_row_in_list_table(self, row_text):
table = self.browser.find_element_by_id('id_list_table')
rows = table.find_elements_by_tag_name('tr')
self.assertIn(row_text, [row.text for row in rows])
def test_can_start_a_list_and_retrieve_it_later(self):
self.browser.get(HEROKU_APP_HOST)
self.browser.get(self.live_server_url)
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertEqual(
......@@ -56,8 +53,31 @@ class NewVisitorTest(unittest.TestCase):
inputbox.send_keys('Activity' + str(i))
inputbox.send_keys(Keys.ENTER)
assert 'oh tidak' in self.browser.page_source
if __name__ == '__main__':
unittest.main(warnings='ignore')
\ No newline at end of file
#assert 'oh tidak' in self.browser.page_source
edith_list_url = self.browser.current_url
self.assertRegex(edith_list_url, '/lists/.+')
self.check_for_row_in_list_table('1: Buy peacock feathers')
# Now a new user, Francis, comes along to the site.
## We use a new browser session to make sure that no information
## of Edith's is coming through from cookies etc #
self.browser.get(self.live_server_url)
page_text = self.browser.find_element_by_tag_name('body').text
self.assertNotIn('Buy peacock feathers', page_text)
self.assertNotIn('make a fly', page_text)
# Francis starts a new list by entering a new item. He
# is less interesting than Edith...
inputbox = self.browser.find_element_by_id('id_new_item')
inputbox.send_keys('Buy milk')
inputbox.send_keys(Keys.ENTER)
# Francis gets his own unique URL
francis_list_url = self.browser.current_url
self.assertRegex(francis_list_url, '/lists/.+')
self.assertNotEqual(francis_list_url, edith_list_url)
# Again, there is no trace of Edith's list
page_text = self.browser.find_element_by_tag_name('body').text
self.assertNotIn('Buy peacock feathers', page_text)
self.assertIn('Buy milk', page_text)
# Satisfied, they both go back to sleep
\ No newline at end of file
stages:
- test
- deploy
- test_functional
- deploy
Test:
image: python:3.7
......@@ -12,7 +12,7 @@ Test:
script:
- python3 manage.py makemigrations
- python3 manage.py migrate
- python3 manage.py test
- python3 manage.py test lists
tags:
- test
......@@ -43,7 +43,6 @@ TestFunctional:
- apt-get install -y xvfb
- wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip
- python manage.py runserver 8000 &
when: on_success
script:
- python3 functional_tests_chrome.py
\ No newline at end of file
- python3 manage.py test functional_tests
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2019-09-23 17:13
# Generated by Django 1.10.5 on 2019-09-29 17:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
......@@ -17,6 +18,18 @@ class Migration(migrations.Migration):
name='Item',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(default='')),
],
),
migrations.CreateModel(
name='List',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
migrations.AddField(
model_name='item',
name='list',
field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='lists.List'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2019-09-23 17:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lists', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='item',
name='text',
field=models.TextField(default=''),
),
]
from django.db import models
# Create your models here.
class List(models.Model):
pass
class Item(models.Model):
text = models.TextField(default='')
\ No newline at end of file
text = models.TextField(default='')
list = models.ForeignKey(List, default=None,on_delete=models.CASCADE)
......@@ -11,24 +11,10 @@
<p>{{bio}}</p>
</div>
<hr>
<h1>Your To-Do list</h1>
<form method="POST">
<h1>Start a new To-Do list</h1>
<form method="POST" action="/lists/new">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
{% csrf_token %}
</form>
{% if items|length == 0 %}
<p>yey, waktunya berlibur</p>
{% elif items|length < 5 %}
<p>sibuk tapi santai</p>
{% else %}
<p>oh tidak</p>
{% endif %}
<table id="id_list_table">
{% for item in items %}
<tr>
<td>{{ forloop.counter }}: {{ item.text }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
\ No newline at end of file
<html>
<head>
<title>To-Do lists</title>
</head>
<body>
<h2>Homepage</h2>
<hr>
<div id="nama_lengkap">Muhammad Ilham Peruzzi</div>
<h5>Bio</h5>
<div>
<p>{{bio}}</p>
</div>
<hr>
<h1>Your To-Do list</h1>
<form method="POST" action="/lists/{{ list.id }}/add_item">
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
{% csrf_token %}
</form>
{% if list.item_set.all|length == 0 %}
<p>yey, waktunya berlibur</p>
{% elif list.item_set.all|length < 5 %}
<p>sibuk tapi santai</p>
{% else %}
<p>oh tidak</p>
{% endif %}
<table id="id_list_table">
{% for item in list.item_set.all %}
<tr>
<td>{{ forloop.counter }}: {{ item.text }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
\ No newline at end of file
......@@ -2,24 +2,37 @@ from django.urls import resolve
from django.test import TestCase
from django.http import HttpRequest
from django.template.loader import render_to_string
from lists.models import Item
from lists.models import Item, List
from lists.views import home_page, about_me
from lists.views import home_page, about_me, view_list
class ItemModelTest(TestCase):
class ListAndItemModelsTest(TestCase):
def test_saving_and_retrieving_items(self):
list_ = List()
list_.save()
first_item = Item()
first_item.text = 'The first (ever) list item'
first_item.list = list_
first_item.save()
second_item = Item()
second_item.text = 'Item the second'
second_item.list = list_
second_item.save()
saved_list = List.objects.first()
self.assertEqual(saved_list, list_)
saved_items = Item.objects.all()
self.assertEqual(saved_items.count(), 2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEqual(first_saved_item.text, 'The first (ever) list item')
self.assertEqual(first_saved_item.list, list_)
self.assertEqual(second_saved_item.text, 'Item the second')
self.assertEqual(second_saved_item.list, list_)
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
......@@ -53,66 +66,96 @@ class HomePageTest(TestCase):
self.assertIn('Bio', html_response)
self.assertTrue(len(about_me()) >= 100)
def test_home_page_can_save_a_POST_request(self):
request = HttpRequest()
request.method = 'POST'
request.POST['item_text'] = 'A new list item'
request.POST['bio'] = about_me()
response = home_page(request)
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new list item')
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], '/')
def test_home_page_only_saves_items_when_necessary(self):
request = HttpRequest()
home_page(request)
self.assertEqual(Item.objects.count(), 0)
def test_home_page_redirects_after_POST(self):
request = HttpRequest()
request.method = 'POST'
request.POST['item_text'] = 'A new list item'
response = home_page(request)
self.assertEqual(response.status_code, 302)
self.assertEqual(response['location'], '/')
def test_home_page_displays_all_list_items(self):
Item.objects.create(text='itemey 1')
Item.objects.create(text='itemey 2')
request = HttpRequest()
response = home_page(request)
self.assertIn('itemey 1', response.content.decode())
self.assertIn('itemey 2', response.content.decode())
def test_automatic_comment_when_no_items(self):
list_ = List.objects.create()
self.assertEqual(Item.objects.count(), 0)
request = HttpRequest()
response = home_page(request)
response = view_list(request,list_.id)
self.assertIn('yey, waktunya berlibur', response.content.decode())
def test_automatic_comment_when_to_do_have_less_five_items(self):
Item.objects.create(text='Activity 1')
Item.objects.create(text='Activity 2')
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
self.assertEqual(Item.objects.count(), 2)
request = HttpRequest()
response = home_page(request)
response = view_list(request,list_.id)
self.assertIn('Activity 1', response.content.decode())
self.assertIn('sibuk tapi santai', response.content.decode())
def test_automatic_comment_when_to_do_have_more_than_or_equal_five_items(self):
Item.objects.create(text='Activity 1')
Item.objects.create(text='Activity 2')
Item.objects.create(text='Activity 3')
Item.objects.create(text='Activity 4')
Item.objects.create(text='Activity 5')
Item.objects.create(text='Activity 6')
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
Item.objects.create(text='Activity 3', list=list_)
Item.objects.create(text='Activity 4', list=list_)
Item.objects.create(text='Activity 5', list=list_)
Item.objects.create(text='Activity 6', list=list_)
self.assertEqual(Item.objects.count(), 6)
request = HttpRequest()
response = home_page(request)
response = view_list(request,list_.id)
self.assertIn('Activity 6', response.content.decode())
self.assertIn('oh tidak', response.content.decode())
\ No newline at end of file
self.assertIn('oh tidak', response.content.decode())
class ListViewTest(TestCase):
def test_uses_list_template(self):
list_ = List.objects.create()
response = self.client.get('/lists/%d/' % (list_.id,))
self.assertTemplateUsed(response, 'list.html')
def test_displays_only_items_for_that_list(self):
correct_list = List.objects.create()
Item.objects.create(text='itemey 1', list=correct_list)
Item.objects.create(text='itemey 2', list=correct_list)
other_list = List.objects.create()
Item.objects.create(text='other list item 1', list=other_list)
Item.objects.create(text='other list item 2', list=other_list)
response = self.client.get('/lists/%d/' % (correct_list.id,))
self.assertContains(response, 'itemey 1')
self.assertContains(response, 'itemey 2')
self.assertNotContains(response, 'other list item 1')
self.assertNotContains(response, 'other list item 2')
def test_displays_all_items(self):
list_ = List.objects.create()
Item.objects.create(text='itemey 1', list=list_)
Item.objects.create(text='itemey 2', list=list_)
def test_saving_a_POST_request(self):
self.client.post('/lists/new',data={'item_text': 'A new list item'})
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/lists/new',data={'item_text': 'A new list item'})
new_list = List.objects.first()
self.assertRedirects(response, '/lists/%d/' % (new_list.id,))
def test_passes_correct_list_to_template(self):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.get('/lists/%d/' % (correct_list.id,))
self.assertEqual(response.context['list'], correct_list)
class NewItemTest(TestCase):
def test_can_save_a_POST_request_to_an_existing_list(self):
other_list = List.objects.create()
correct_list = List.objects.create()
self.client.post(
'/lists/%d/add_item' % (correct_list.id,),
data={'item_text': 'A new item for an existing list'}
)
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new item for an existing list')
self.assertEqual(new_item.list, correct_list)
def test_redirects_to_list_view(self):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.post('/lists/%d/add_item' % (correct_list.id,),data={'item_text': 'A new item for an existing list'})
self.assertRedirects(response, '/lists/%d/' % (correct_list.id,))
"""superlists URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.10/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from lists import views
urlpatterns = [
url(r'^(\d+)/$', views.view_list, name='view_list'),
url(r'^(\d+)/add_item$', views.add_item, name='add_item'),
url(r'^new$', views.new_list, name='new_list'),
]
from django.shortcuts import render, redirect
from django.http import HttpResponse
from lists.models import Item
from lists.models import Item, List
# Create your views here.
......@@ -8,15 +8,24 @@ response = {}
def home_page(request):
html = 'homepage.html'
response["bio"] = about_me()
if request.method == 'POST':
Item.objects.create(text=request.POST['item_text'])
return redirect('/')
items = Item.objects.all()
return render(request, html, {'bio':about_me(),'items': items})
return render(request, html, {'bio':about_me()})
def about_me():
return "Hello. My name is Muhammad Ilham Peruzzi. \
I am now study at Faculty of Computer Science, University of Indonesia, since 2016.\
I like to read books and listening the music. Now I am learning about how to make a \
test in Software Quality Assurance class and this is my first practice."
\ No newline at end of file
test in Software Quality Assurance class and this is my first practice."
def view_list(request, list_id):
list_ = List.objects.get(id=list_id)
return render(request, 'list.html', {'list': list_,'bio':about_me()})
def new_list(request):
list_ = List.objects.create()
Item.objects.create(text=request.POST['item_text'], list=list_)
return redirect('/lists/%d/' % (list_.id,))
def add_item(request, list_id):
list_ = List.objects.get(id=list_id)
Item.objects.create(text=request.POST['item_text'], list=list_)
return redirect('/lists/%d/' % (list_.id,))
\ No newline at end of file
......@@ -13,11 +13,11 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.conf.urls import url, include
from django.contrib import admin
from lists import views
from lists import views, urls
urlpatterns = [
url(r'^$', views.home_page , name='home'),
#url(r'^admin/', admin.site.urls),
url(r'^lists/', include('lists.urls')),
]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment