CS50‘s Web Programming with Python and JavaScript學習筆記: Testing, CI/CD

Testing, CI/CD

Testing

import mathdef is_prime(n):
"""Determines if a non-negative integer is prime."""
if n < 2:
return False
for i in range(2, int(math.sqrt(n)):
if n % i == 0:
return False
return True
from prime import is_primedef test_prime(n, expected):
if is_prime(n) != expected:
print(f"ERROR on is_prime({n}), expected {expected}")
from prime import is_primedef test_prime(n, expected):
if is_prime(n) != expected:
print(f"ERROR on is_prime({n}), expected {expected}")
if __name__ == "__main__":
test_prime(-4, False)
test_prime(-3, False)
test_prime(-2, False)
test_prime(-1, False)
test_prime(0, False)
test_prime(1, False)
test_prime(2, True)
test_prime(3, True)
test_prime(4, False)
for i in range(2, int(math.sqrt(n) + 1):
if n % i == 0:
return False
import mathdef is_prime(n):
return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))

assert

unittest

Testing Web Applications with Django

# Add a method that raises "Validation errors" if the data is illogical.
def clean(self):
if self.origin == self.destination:
raise ValidationError("Origin and destination must be different.")
elif self.duration < 1:
raise ValidationError("Duration must be positive.")
# Call this method before trying to add data, overriding the default behavior of built-in `save`.
def save(self, *args, **kwargs):
self.clean()
# This syntax now calls Django's own "save" function, adding this data to the DB (if `clean` was ok).
super().save(*args, **kwargs)

Selenium

<html>
<head>
<title>Counter</title>
<script>
document.addEventListener('DOMContentLoaded', () => { let counter = 0; document.querySelector('#increase').onclick = () => {
counter++;
document.querySelector('h1').innerHTML = counter;
};
document.querySelector('#decrease').onclick = () => {
counter--;
document.querySelector('h1').innerHTML = counter;
};
});
</script>
</head>
<body>
<h1>0</h1>
<button id="increase">+</button>
<button id="decrease">-</button>
</body>
</html>
import os
import pathlib
import unittest
from selenium import webdriver# A convenience function to turn a filename into a full path, as needed for a browser
def file_uri(filename):
return pathlib.Path(os.path.abspath(filename)).as_uri()
driver = webdriver.Chrome()class WebpageTests(unittest.TestCase): def test_title(self):
driver.get(file_uri("counter.html"))
self.assertEqual(driver.title, "Counter")
def test_increase(self):
driver.get(file_uri("counter.html"))
increase = driver.find_element_by_id("increase")
increase.click()
self.assertEqual(driver.find_element_by_tag_name("h1").text, "1")
def test_decrease(self):
driver.get(file_uri("counter.html"))
decrease = driver.find_element_by_id("decrease")
decrease.click()
self.assertEqual(driver.find_element_by_tag_name("h1").text, "-1")
def test_multiple_increase(self):
driver.get(file_uri("counter.html"))
increase = driver.find_element_by_id("increase")
for i in range(3):
increase.click()
self.assertEqual(driver.find_element_by_tag_name("h1").text, "3")
if __name__ == "__main__":
unittest.main()

Continuous Integration and Continuous Delivery

key1: value1
key2: value2
key3:
- item1
- item2
- item3
key4:
nested_key1: value3
nested_key2:
- item4
- item5
language: python
python: 3.6
install: pip install -r requirements.txt
script: python manage.py test

Continuous Deployment

Deploying our app to Heroku:

Required files for Heroku

web: gunicorn <PROJECT NAME>.wsgi

Using Travis to allow for Continuous Delivery of our Application

deploy:
provider: heroku
api_key: $HEROKU_API_KEY
app: APP
run: python manage.py migrate
on: master

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store