Project_Demo / tests /test_lesson21_template.py
steveyehtw's picture
Publish standalone Lesson 21 starter for students continuing from Lesson 19
271e6aa
Raw History Blame Contribute Delete
3.44 kB
import contextlib
import io
import json
import runpy
import shutil
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
TEMPLATE = ROOT / "classroom_data/templates/week21"
class Lesson21TemplateTests(unittest.TestCase):
def setUp(self):
self.lesson = runpy.run_path(str(TEMPLATE / "main.py"))
self.rows = self.lesson["load_rows"](TEMPLATE / "data/students_by_county.csv")
def run_starter(self, county="新北市", completed=False):
with tempfile.TemporaryDirectory() as directory:
project = Path(directory) / "project"
shutil.copytree(TEMPLATE, project, ignore=shutil.ignore_patterns("__pycache__"))
source = (project / "main.py").read_text(encoding="utf-8")
source = source.replace('COUNTY = "新北市"', f'COUNTY = "{county}"')
if completed:
source = source.replace("change = None", "change = after - before")
(project / "main.py").write_text(source, encoding="utf-8")
result = subprocess.run([sys.executable, "-B", "main.py"], cwd=project,
capture_output=True, text=True, timeout=10)
self.assertEqual(result.returncode, 0, result.stderr)
return result.stdout
def test_lesson_is_enabled_without_changing_existing_workspace(self):
course = json.loads((ROOT / "classroom_data/course.json").read_text(encoding="utf-8"))
lessons = {item["id"]: item for item in course["weeks"]}
self.assertTrue(lessons["week21"]["template"])
self.assertEqual(lessons["week21"]["workspace_id"], "week19")
self.assertEqual(lessons["week20"]["workspace_id"], "week19")
self.assertTrue((TEMPLATE / "REPORT.md").is_file())
self.assertTrue((TEMPLATE / "DATA_SOURCE.md").is_file())
def test_starter_runs_before_student_fills_in_the_calculation(self):
output = self.run_starter()
self.assertIn("讀入 242 列資料", output)
self.assertIn("201,970 人", output)
self.assertIn("194,670 人", output)
self.assertIn("請完成 change", output)
self.assertNotIn("增減人數:", output)
def test_completed_examples_match_the_lesson_slides(self):
self.assertIn("增減人數:-7,300 人", self.run_starter(completed=True))
self.assertIn("增減人數:+4,060 人", self.run_starter("臺中市", completed=True))
def test_rankings_use_the_supplied_dataset(self):
results = self.lesson["count_by_county"](self.rows, "114", "國小[人]")
self.assertEqual(results[:3], [("新北市", 194670), ("臺中市", 161332), ("桃園市", 132964)])
def test_unknown_counts_are_not_zero_and_zero_chart_does_not_divide(self):
for value in ("", "-", "未知", None):
self.assertIsNone(self.lesson["parse_count"](value))
self.assertEqual(self.lesson["parse_count"]("0"), 0)
self.assertEqual(self.lesson["parse_count"](" 1,234 "), 1234)
self.assertIsNone(self.lesson["get_count"](self.rows, "999", "新北市", "國小[人]"))
with contextlib.redirect_stdout(io.StringIO()):
self.lesson["print_text_chart"]([("甲", 0), ("乙", 0)])
self.assertIn("找不到完整的兩筆人數", self.run_starter("不存在的縣市", completed=True))
if __name__ == "__main__":
unittest.main()