Closed61

TDD と Django 学習経過報告

パダワンパダワン

開始日:2021年12月1日

  • 正確な日時がわからないので、切りよく。

費用

  • 例により、ACM 経由 で年間 $ 99 ( 約 12000 円程度) で会員登録した。
  • 月額約1000円とすれば、とても安く感じる。

懸念点

  • 本は、何度も何度も見返す事が多く、またそのときは理解できなかったことも、あとから再読して理解できるということがある。
  • そうなったとき解約していたらどうするか。 読み返すということは良書なので、買っても割に合うのかもしれない。
パダワンパダワン

進捗報告

  • ザッピングして、目次を読むだけにとどまっている。
  • どの本を読み始めるか考えている。
  • 目標が必要だと考え、仮に現在興味を持ち始めた TDD について理解が進むような本を読めれば、良いと思った。
  • 課題点1:何しろ進みが遅い
  • 課題点2:つまみ食いするべきか、初めから読みすすめるべきか、決めかねている。

リストアップ

  • "Test-Driven Development with Python: Obey the Testing Goat: Using Django, Selenium, and JavaScript"
    • TDD x Django の本

目次を読む理由

  • その本を読みすすめる前に、目次を読み、目次が理解できない本は、その時点ではまだ早いという印なので、より簡単で軽い本を先にサッと読むのが良いというコツを読書家が勧めていたため。

「課題点2:つまみ食いするべきか、初めから読みすすめるべきか、決めかねている。」について

  • はじめから読み勧めて、読み通せたことが数えるくらいしかない。
  • 集中力というより、一度中断して、再度そこから読み始めるエネルギーがない。
  • 成功する場合は、気になるところだけを先につまみ食いをし、それを何度もして、全体の形が気になってから、最初から読み始め、すでに読んだところは理解しているところはさっと読み、全体を読む、という方法。
パダワンパダワン

方針:通読しない

  • 現在、Django のアプリケーションを業務で作って入るが、UI やフロントエンドの開発というよりも、アプリケーションのロジックに近い部分、それもごくごく一部のメソッドを触らせてもらえているだけ。
  • 構造的な理解はするに越したことはないが、
    1. やる気が持続しない(つらい)
    2. 洋書はエネルギーを使う
  • これらの理由から、通読はせず目的を明確化して、部分的に読んでいく。
    • 読みたくなったら(必要になったら)、その部分も読む。
      • 再帰的、落下傘的とも
パダワンパダワン

概要の理解

  • 通読しないが、どんな本かを理解しているに越したことはない。
  • まえがき、あとがき、目次は軽く読んでおきたい。
パダワンパダワン

調査:Django1 と Django3 の違い

Django1 と Django2

大きな変更点としては、Python 2 のサポートが打ち切られた
URLconf の書き方が簡単になった(django.urls.path() が追加)
モデルの ForeignKey と OneToOneField で「on_delete」オプションが必須に

あまり大きな変化はないらしい。

Django2 と Django3

  • 上記のブログエントリーで、メジャーバージョンのリリースノートを観るという王道を知ったため、自分で確認してみる。

Django 3.0 release notes

  • Model.save() when providing a default for the primary key¶
  • Database backend API¶
  • django.contrib.admin¶
  • django.contrib.gis¶
  • Dropped support for PostgreSQL 9.4¶
  • Dropped support for Oracle 12.1¶
  • Removed private Python 2 compatibility APIs¶
  • New default value for the FILE_UPLOAD_PERMISSIONS setting¶
  • New default values for security settings¶
  • その他

結論

  • ちょっとよくわからない。Django チュートリアル(v3.2) をやっただけなので、あまり気にしてはいけないが、わからないのはつらい。
  • admin や セキュリティセッティングの default value などは、参考書を写経する過程で再現できないとき、明確に設定されない、これらの変更点が原因になりそうだ。
  • 明確な変更の参照点がわかったので、困ったらここを見ればいいようだ。

参考リンク

パダワンパダワン

サボっている。

  • スマホでのみやすさ。
    • スマホで見るのは若干辛い。
    • すぐに翻訳できる
    • すぐに読める
  • カラーでない場合が多いことが、若干ストレス。
パダワンパダワン

CHAPTER 1 Getting Django Set Up Using a Functional Test

  • TDD is discipline, like martial art. Just like in a Kung fu movie.
  • Our master is Testing Goat.

Obey the Testing Goat! Do nothing Until You Have a Test.

  • Testing Goat bleating "Test first, test first!"
  • In TDD the first step is always the same: write a test
  • First, we write the test: then we run it and check that it fails as expected.
  • Only then do we go ahead and build some of our app.
  • Another thing about goats is that they take one step at a time.

英単語

  • discipline: 訓練
  • seldom: めったにない
  • no matter how: どんなに
  • steep: 急ぐ
パダワンパダワン
  • The first thing we want to do is check that we've got Django installed.
    • 初めにすることは Django が適切にインストールできたか、確認すること。
    • あれやこれやをインストールすることではない。
  • The way we'll check is by confirming that we can spin up Django's development server and actually see it serving up a web page, in our web browser, on our local PC.
    • 確認するために、Django サーバーを立ち上げ、ウェブページを表示していることをローカル PC から確認する。

英単語

  • spin up: 新しく既存のものを立ち上げる。一般的ではない。
パダワンパダワン
  • M1 Mac
  • Docker
  • selenium
  • Firefox / GoogleChrome

これらのインストールに手間取りまくっている。

パダワンパダワン

selenium の imageを元にして、色々継ぎ接ぎしたせいで、ごちゃごちゃになった。

Dockerfile

# 元となるdockerイメージを指定
# M1 は `selenium/standalone-chrome` が使えないため
FROM seleniarm/standalone-chromium:4.0.0-20211213

# 管理者ユーザ docker の設定
RUN sudo useradd -m docker && echo "docker:docker" | sudo chpasswd && sudo adduser docker sudo
USER docker
# USER $HOME_USER

# この環境変数に値を入れることでバッファを無効化する('1'じゃなくてもいい)
ENV PYTHONUNBUFFERED 1
# codeディレクトリを作成
RUN sudo mkdir /code
# codeディレクトリに移動
WORKDIR /code
# txtファイルをcodeディレクトリに配置
COPY requirements.txt /code/

# パッケージインストーラ
# requirements.system に対象パッケージ記入
COPY requirements.system /tmp/requirements.system
RUN sudo apt-get update \
    && sudo xargs apt-get install -y --no-install-recommends \
        < /tmp/requirements.system \
    && sudo apt-get -y clean \
    && sudo rm -rf /var/lib/apt/lists/*
# pipコマンドを最新にし、txtファイル内のパッケージをpipインストール
RUN pip install --upgrade pip \
    && pip install -r requirements.txt

# sample-pj/配下のファイルをcodeディレクトリにコピー
COPY . /code/

CMD "/bin/bash"

起動コマンド

$ docker run -it -w . -v $(pwd):/usr/workspace joyzoursky/python-chromedriver:latest bash
docker ps -a でしらべる 

以下はどっちでやったかわからない。
$ docker run --rm -it -p 4444:4444 -p 5901:5900 -p 7900:7900 --shm-size 3g django_tdd_web
$ docker-compose up -d
$ docker ps -a
$ docker exec -it [コンテナID] bash
  • vscode の shell では履歴が残りにくいため、terminalアプリのほうでやりたい。
    • これは bash の履歴を ホストのマシンと共有すればよいのかもしれないが、それはまた別の機会にやりたい。
パダワンパダワン

とにもかくにも、first step: seleniumによる起動のテストはできた。

パダワンパダワン

TDD のおさらい

  1. selenium により、django で起動したweb アプリへアクセスし、asset 条件 サイトのタイトルが Djangoを満たすか検証するテスト を作成
  2. テストを実行し、失敗することを確認
  3. Django サーバーを起動、(+ migration)
  4. テストを再度実行し、成功することを確認
  • failing test -> allow to start building app
  • 失敗するテストを作って初めて、開発を始める。
パダワンパダワン

起動確認の方法

  • selenium は webdriver を選択する。今回は chrome
  • 原本には、firefox を使っているが、個人的には webdriver は chrome を使いたい。理由としては、テストは実際にユースケースに近いほうが良いためだ。webdriver が違えば、レンダリングエンジンや諸々がかなり異なるため、テストには一番メジャーなものを使うべきだと思う。
  • ちなみにシェアを調べたところ、2021年10月時点では、Chrome:65.2%、Firefox:3.8%らしい。(https://shiftasia.com/ja/column/2021年10月webブラウザシェア/)
$ python manage.py functional_tests.py
from selenium import webdriver

browser = webdriver.Chrome()
browser.get('http://localhost:8000')

assert 'Django' in browser.title

上記では動かなかった。

  • headless オプションを使わないといけないらしい。
  • ブラウザとしての window などフロントエンドを立ち上げないということらしい。
  • 普段のブラウジングではなく、クローリングや、今回のようなテストに使うためには必要な設定のようだ。
from selenium import webdriver
#Optionsクラスのインポート(ヘッドレスの設定をするため)
from selenium.webdriver.chrome.options import Options

#Optionsのインスタンスを生成(変数optionsに格納)
options = Options()

#headlessの設定をTrueにする
options.headless = True

#webdriverの起動
browser = webdriver.Chrome(options=options)
browser.get('http://localhost:8000')

assert 'Django' in browser.title
パダワンパダワン

Getting Django Up and Running

  • django のパスの通し方がよくわからず、find grep で絶対パスを探して実行した。
docker@74e13d35dd90:/code$ python /home/seluser/.local/lib/python3.9/site-packages/django/bin/django-admin.py startproject superlists

パダワンパダワン

CHAPTER 2 Extending Our Functional Test Using the unittest Module

  • unit test の拡張
  • Tests that use Selenium let us drive a real web browser, so they really let us see how the application functions from the user’s point of view. That’s why they’re called functional tests.
  • This means that an FT can be a sort of specification for your application.
    • これはつまり、機能テスト(FT)はアプリの仕様のようなものであることを意味します。
  • It tends to track what you might call a User Story, and follows how the user might work with a particular feature and how the app should respond to them.
    • ユーザーストーリーと呼ばれるものに追跡する?傾向があり、
    • どのように特定の特徴(機能)を動作させ、アプリがどのようにそれに応答するべきかを示します。

英単語

  • a sort of : 一種の~~。~~のようなもの。
パダワンパダワン

用語の説明

  • 機能テスト(Functional Test)
  • 受け入れテスト(Acceptance Test)
  • End To End テスト

これらはほぼ同じ意味で使われる。
アプリケーションの動作を外からテストすること。

パダワンパダワン

Using a Fungtional Test to Scope Out a Minimum Viable app

  • FT は私達が追えるような"人が読める"ストーリー が必要です。

  • 私達は、テストに付随するコメントでそれを明示します。

  • 新しい FT を作るとき、まず最初にコメントを書いて、ユーザーストーリーの重要なポイントを把握することができます。

  • "人が読める"ため、プログラマーでないひと、アプリの要件や機能を議論する方法として、コメントを共有することができます。

  • TDDとアジャイルソフトウェア開発手法はよく一緒に使われますが、その際によく話題にするのが、"最小限の実行可能なアプリ"です。

  • できるだけ早く作って、テストしてみましょう。

英単語

  • Minimum Viable app: (最小限の)
  • explicit : 明確な、明示する
  • accompany: 付随する
  • point out : 指摘する
  • requirements: 要件
  • feature: 機能
パダワンパダワン

Minimum Viable To-Do List

  • 実行可能な最小限の To-Do アプリ
    • ユーザーがいくつかの To-Do 項目を入力できる
    • 次回まで項目を記録しておくこと
パダワンパダワン

ユーザーストーリー

  • 原本には以下のようなものをコメントに書いている。

彼女はすぐにToDoを入力するように誘われる
彼女はテキストボックスに「Buy peacock feathers」と入力する(Edithの趣味はフライフィッシングのルアーを結ぶことである)。
Enterキーを押すと、ページが更新され、ToDoリストの項目として「1: クジャクの羽を買う」が表示されるようになりました。
まだテキストボックスがあり、別の項目を追加することができます。
彼女は「Use peacock feathers to make a fly」と入力した(Edithはとても几帳面だ)。
再びページが更新され、リストの2つの項目が表示された イーディスは、サイトが自分のリストを覚えているのかどうか疑問に思った。
すると、サイトが自分用にユニークなURLを生成していることがわかりました。
そのURLにアクセスすると、ToDoリストはまだそこにある。
満足して眠りにつく

パダワンパダワン

上記は DeepL を使った自動翻訳であるため、少し修正する。

Unit test にユーザーストーリーを記述する。

  • 行動(振る舞い)駆動開発 Behaviour-Diriven Development という概念が発展している。
from selenium import webdriver
#Optionsクラスのインポート(ヘッドレスの設定をするため)
from selenium.webdriver.chrome.options import Options

#Optionsのインスタンスを生成(変数optionsに格納)
options = Options()

#headlessの設定をTrueにする
options.headless = True

#webdriverの起動
browser = webdriver.Chrome(options=options)

# エディスさんはクールな To-Do アプリの話を聞き、
# 彼女はホームページをチェックしに行った。
browser.get('http://localhost:8000')

# 彼女はページタイトルとヘッダーが To-Do に言及している事に気づいた。
assert 'To-Do' in browser.title

# 早速、To-Do アプリへ項目を入力したくなる。

# テキストボックスに「孔雀の羽毛を買う」と入力する
# (エディスの趣味は、羽で釣りのルアーを作ること。)

# エンターキーを押すと、ページが更新され、次のようなことが表示される。
# To-Do リストの項目「1: 孔雀の羽毛を買う」

# まだテキストボックスは残っていて、項目を追加できる。
# 彼女は「孔雀の羽を使ってルアーを作る」と入力した。(彼女は几帳面だ)

# 再びページが更新され、リストの2つの項目が表示された。

# エディスは、サイトが自分のリストを記憶しているか疑問に思った。
# そしてサイトが自分用のユニークなURLを生成している事を確認しました。
# (その説明文が表示されている。)

# 満足した彼女は眠りにつく。

browser.quit()
パダワンパダワン

コメントについて

  • コメントは、コメントがコードの変更に合わせてメンテナンスされないと、混乱のもとになる。
  • 理想は、コードの変数や、構造、などコード自体の処理の明確さにより説明がなされるべき。
  • (別の本だが、コメントでは、なぜこうではないのか、などコードでは説明できない意図をコメントすると良いらしい。)
パダワンパダワン

it’s pointless to write a comment that just repeats what you’re doing with the code:
コードの説明の繰り返しとなるコメントは書かないほうがいい。

パダワンパダワン

Test to fail == expected fail

  • 現状のunit test は、実装と異なる点がある。
    • タイトルがDjango->To-Do
  • よって、テストが失敗することが期待値である。
$ docker exec -it 8ede61c86d93 bash
$ docker@8ede61c86d93:/workspaces/django_tdd/superlists$ python manage.py runserver 0.0.0.0:8000
docker@8ede61c86d93:/workspaces/django_tdd$  cd /workspaces/django_tdd ; /usr/bin/env /usr/bin/python3 /home/seluser/.vscode-server/extensions/ms-python.python-2021.12.1559732655/pythonFiles/lib/python/debugpy/launcher 35221 -- functional_tests.py 
Traceback (most recent call last):
  File "/workspaces/django_tdd/functional_tests.py", line 19, in <module>
    assert 'To-Do' in browser.title
AssertionError
  • 期待通りの結果が得られた。
パダワンパダワン
  • テストが実際に機能しているということがこれにより自信が持てます。
パダワンパダワン

The Python Standard Library’s unittest Module

  • エラーのメッセージなどが貧弱なので、 Unittest モジュールを導入します。
  • setUp, tearDown はテストの最初と最後に実行されます。
    • テストが途中でエラーになり、落ちたとしても実行されるため、ブラウザが起動し続けることがありません。
from unittest.main import main
from selenium import webdriver
#Optionsクラスのインポート(ヘッドレスの設定をするため)
from selenium.webdriver.chrome.options import Options
import unittest

class NewVisitorTest(unittest.TestCase):
    def setUp(self) -> None:
        #Optionsのインスタンスを生成(変数optionsに格納)
        self.options = Options()
        #headlessの設定をTrueにする
        self.options.headless = True
        #webdriverの起動
        self.browser = webdriver.Chrome(options=self.options)

    def tearDown(self):
        self.browser.quit()

    def test_can_start_a_list_and_retrieve_it_later(self):
        """
        ユーザはリストを作成し、後に取得することができる。
        """
        # エディスさんはクールな To-Do アプリの話を聞き、
        # 彼女はホームページをチェックしに行った。
        self.browser.get('http://localhost:8000')

        # 彼女はページタイトルとヘッダーが To-Do に言及している事に気づいた。
        self.assertIn('To-Do', self.browser.title)
        self.fail('Finish the test!')

        # 早速、To-Do アプリへ項目を入力したくなる。

        # テキストボックスに「孔雀の羽毛を買う」と入力する
        # (エディスの趣味は、羽で釣りのルアーを作ること。)

        # エンターキーを押すと、ページが更新され、次のようなことが表示される。
        # To-Do リストの項目「1: 孔雀の羽毛を買う」

        # まだテキストボックスは残っていて、項目を追加できる。
        # 彼女は「孔雀の羽を使ってルアーを作る」と入力した。(彼女は几帳面だ)

        # 再びページが更新され、リストの2つの項目が表示された。

        # エディスは、サイトが自分のリストを記憶しているか疑問に思った。
        # そしてサイトが自分用のユニークなURLを生成している事を確認しました。
        # (その説明文が表示されている。)

        # 満足した彼女は眠りにつく。

if __name__ == '__main__':
    unittest.main(warnings='ignore')
パダワンパダワン

warnings='ignore' suppresses a superfluous ResourceWarning which was being emitted at the time of writing.
It may have disappeared by the time you read this; feel free to try removing it!

  • これはちょっとよくわからない。
  • WARNING が多すぎても害なのは、実際に業務を行っていて感じるため、同意する点。

英単語

  • suppress: (動詞) 表示しない。← 鎮圧とかを意味する。Tech だと違うらしい。
  • superfluous: 過剰な
  • be emitted: 出力される
パダワンパダワン

First FT specced out in comments, and now uses unittest.

  • 最初はコメントで機能テスト(FT)を仕様化?し、現在はユニットテストを使用している。

英単語

  • Substantially: 大幅な(変更、変化)
  • Quite: かなり
  • Bonzer: すばらしい(オーストラリア英語)
  • spec out←よくわからない。
パダワンパダワン
  • コメントによるユーザーストーリーの記述
  • 箇条書きのユーザーストーリーによる機能テストの記述
  • unittest moduleによるテスト環境構築
  • fail test の実行と結果の確認
  • 上記により、本実装(real code)の準備が整った。
パダワンパダワン

Useful TDD Concepts (便利な TDD の概念)

User Story (ユーザーストーリー)

A description of how the application will work from the point of view of the user. Used to structure a functional test.

  • ユーザーからの視点で、どのようにアプリケーションが振る舞うかを記述したもの。
  • 機能テストを作成するために用いる。

Expected failure (期待された失敗)

When a test fails in the way that we expected it to.

パダワンパダワン

CHAPTER 3 Testing a Simple Home Page with Unit Tests

Warning: Things Are About to Get Real とは

  • DeepL で翻訳したところ、上記の題は「ご注意: これからが本番です」となった。これは本当にすごい意訳だ。
  • しかし、調べると、一種の言い回しのようである。https://hinative.com/en-US/questions/12402108
  • これからなにか大きなことが起こることを、それを知らない人に告げるときなどに使うようだ。

コラム:Warning: Things Are About to Get Real

The first two chapters were intentionally nice and light.
From now on, we get into some more meaty coding.

  • meaty: 本格的な

Here’s a prediction: at some point, things are going to go wrong.
You’re going to see different results from what I say you should see.
This is a Good Thing, because it will be a genuine character-building Learning ExperienceTM.

  • character-building Learning Experience: 経験学習による人格形成、 人格形成のための学習経験

One possibility is that I’ve given some ambiguous explanations, and you’ve done something different from what I intended.

  • ambiguous: あいまいな

Step back and have a think about what we’re trying to achieve at this point in the book.
Which file are we editing, what do we want the user to be able to do, what are we testing and why?
It may be that you’ve edited the wrong file or function, or are running the wrong tests.
I reckon you’ll learn more about TDD from these “stop and think” moments than you do from all the bits where the following instructions and copy-pasting goes smoothly.

Or it may be a real bug.
Be tenacious, read the error message carefully (see “Reading Tracebacks” on page 27 a little later on in the chapter), and you’ll get to the bottom of it.
It’s probably just a missing comma, or trailing slash, or maybe a missing s in one of the Selenium find methods.
But, as Zed Shaw put it so well, this kind of debugging is also an absolutely vital part of learning, so do stick it out!

  • 学習過程において、エラーメッセージを読むなどして、粘り強くデバッグをするということが重要な成長の一部である。

英単語

  • last: 前の(最後の)
パダワンパダワン

Our First Django App, and Our First Unit Test

  • Django はアプリ単位での構造化を推奨しています。
  • Django はアプリにより、再利用可能性を高めています。
  • サードパーティ製のアプリも組み込めます。

自分たちの to-do リストのために、app を開始しましょう。

$ python manage.py startapp lists

英単語

  • encourage: 推奨
  • admit: 認める
  • code organised: コードを整理する
パダワンパダワン

Unit Tests, and How They Differ from Functional Tests

  • ユニットテストと機能テストの違い
  • ユニットテストは単体テストとも呼ばれるらしい。
  • 両方のテストをTDDでは用いる。

機能テスト

  • アプリケーションを外側から
  • ユーザ視点でテストする

ユニットテスト

  • アプリケーションを内側から
  • プログラマー視点でテストする

英単語

  • blurry: あいまい
  • distinction: 区別
パダワンパダワン

TDD workflow

  1. 初めに機能テストを書き、ユーザ視点で新しい機能を表現する。
  2. 失敗する機能テストを作ったら、どうやってテストをpassするコードを書けば良いか考え始める。
  • もしくは、最低でも現在の失敗を克服する
  • ユニットテストを使ってコードの振る舞いを定義する。
  1. 失敗するユニットテストができたら、ユニットテストを pass するのに十分な最小限のアプリケーションコードを書く。
  • 機能テストがもう少し先に進んだと思えるまで、ステップ2, ステップ3 の間を行き来するかもしれません。

We may iterate between steps 2 and 3 a few times, until we think the functional test will get a little further.

  1. ユニットテストが通ったことを確認した、もしくはもう少し先にすすめられることを確認したら、そうすると新しいコードや、ユニットテストを書くことになるかもしれません。

You can see that, all the way through, the functional tests are driving what development we do from a high level, while the unit tests drive what we do at a low level.

  • 機能テストは、ハイレベル(高い抽象度)
  • ユニットテストは、ローレベル

Does that seem slightly redundant? Sometimes it can feel that way, but functional tests and unit tests do really have very different objectives, and they will usually end up looking quite different.

  • 少し冗長に感じるでしょうか
  • しかしそれらは違う目的を持っており、通常、見た目も異なります。
    ↑何を言っているの?

Tips

Functional tests should help you build an application with the right functionality, and guarantee you never accidentally break it. Unit tests should help you to write code that’s clean and bug free.

  • 機能テストは、正しく機能を実装することを助け、アプリケーションが予期せず壊してしまわないことを保証します。
  • ユニットテストは、クリーンでバグがないコードを書くために役立つはずです。

英単語

  • get past : 乗り越える
  • further: さらに、よりいっそう、先に進む
  • should: はず
パダワンパダワン

At Last! We Actually Write Some Application Code!

Be warned, TDD means that long periods of anticipation are only defused very gradually, and by tiny increments.

  • TDD は長期間の目標を少しずつしか解消できないことを注意してください。
パダワンパダワン

I’m being deliberately extreme here, but what’s our current test failure?

  • ここでわざと極端なことを言いますが、私達のテストの失敗は何でしょうか。

“You must be joking!”
Well, bear with me, and we’ll talk about whether or not this is all taking it too far in a little while.
But for now, let yourself follow along, even if it’s with some exasperation, and see if our tests can help us write the correct code, one tiny step at a time.

  • テストが正しいコードを書くのに役立つかどうか、一度に小さな一歩ずつ見ていきましょう。

英単語

  • all taking it too far : 行き過ぎ
  • bear with me : 我慢する
  • let yourself follow along : 従わせる
  • exasperation : 苛立ち
パダワンパダワン

The traceback is messy, but the message at the end is telling us what’s going on: the unit tests have actually made the link between the URL “/” and the home_page = None in lists/views.py, and are now complaining that the home_page view is not calla‐ ble. And that gives us a justification for changing it from being None to being an actual function. Every single code change is driven by the tests!

  • ユニットテストは、URL "/" と lists/views.py の home_page = None の間のリンクを実際に作成し、 home_page ビューが呼び出されないことに文句を言っているのです。そしてそれが、Noneから実際の関数に変更する正当な理由になっています。すべてのコードの変更は、テストによって推進されます!
パダワンパダワン

上のような DeepL そのまま貼り付けると意味不明になってしまう。ゆくゆくはそのまま読めるように英語の勉強を兼ねているため、コピペは避けよう。

パダワンパダワン

The Unit-Test / Code Cycle

  1. In the terminal, run the unit tests and see how they fail.
  2. In the editor, make a minimal code change to address the current test failure.
    And repeat!
    1. unit test を実行し、どのように fail するかを見る。
    1. エディタで現在のコードの失敗に対処するために、最小のコード変更を行う。
  • そしてその繰り返し!

The more nervous we are about getting our code right, the smaller and more minimal we make each code change
the idea is to be absolutely sure that each bit of code is justified by a test.

  • コードを正しく実装することに神経質になればなるほど、コードの変更は小さく、最小限になる。
  • 考え方はコードの各bit がテストにより正当化されることを、絶対に確認することです。

英単語

  • settle into : 定着する
  • more ~ , more ~
  • justifie : 正当化する
  • minimal code change : 最小限のコードの変更
パダワンパダワン

テスト実行のパス

launch.json
"cwd": "${workspaceFolder}"

ワークスペースをテスト実行時のルートにできる。

unit test に参照するライブラリを相対パスで書いていると混乱してくる。

自分の場合、直書きして、事なきを得た。

パダワンパダワン

進捗報告:

以下の Unit Test を先に書き、View の実装を進める。

def test_home_page_returns_correct_html(self): 
  request = HttpRequest()
  response = home_page(request)  html = response.content.decode('utf8')
  self.assertTrue(html.startswith('<html>')) 
  self.assertIn('<title>To-Do lists</title>', HTML)
  self.assertTrue(html.endswith('</html>'))
パダワンパダワン

進捗報告:Firefox に戻した。

chrome ドライバが思った挙動をしないため、Firefoxをインストールした。

作者の言う通り、Firefox を Crome にしたり、余計なことはしないほうがいいと思った。

Firefox ヘッダーレス?

setup.sh
sudo apt update
sudo apt install firefox python3-pip xvfb x11-utils --yes
sudo -H pip3 install bpython selenium

export DISPLAY=:2
Xvfb $DISPLAY -ac &

export GECKO_DRIVER_VERSION='v0.24.0'
wget https://github.com/mozilla/geckodriver/releases/download/$GECKO_DRIVER_VERSION/geckodriver-$GECKO_DRIVER_VERSION-linux64.tar.gz
tar -xvzf geckodriver-$GECKO_DRIVER_VERSION-linux64.tar.gz
rm geckodriver-$GECKO_DRIVER_VERSION-linux64.tar.gz
chmod +x geckodriver
sudo cp geckodriver /usr/local/bin/

cat <<EOF > script.py
#!/usr/bin/env python3
from selenium.webdriver import Firefox, FirefoxOptions, FirefoxProfile

ff_options = FirefoxOptions()
ff_options.headless = True

ff = Firefox(options=ff_options)
ff.quit()
EOF
chmod +x script.py
``
パダワンパダワン

Test is failure !

  • サーバーをローカルで立ち上げ、それが目標とする振る舞いをしているかを、機能テストによって確認した!

$ python manage.py runserver
$ python functional_tests.py
↓
$  /usr/bin/env /usr/bin/python3 /home/seluser/.vscode-server/extensions/ms-python.python-2022.4.1/pythonFiles/lib/python/debugpy/launcher 33227 -- functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
ユーザはリストを作成し、後に取得することができる。
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 31, in test_can_start_a_list_and_retrieve_it_later
    self.fail('Finish the test!')
AssertionError: Finish the test!

----------------------------------------------------------------------
Ran 1 test in 2.891s

感想

サーバーを立ち上げるのを忘れていたが、それも機能テストの一部に以下の項目があったため、fail したエラー文を読むことで気づけた。これもテストのメリットか

        # エディスさんはクールな To-Do アプリの話を聞き、
        # 彼女はホームページをチェックしに行った。
        self.browser.get('http://localhost:8000')
パダワンパダワン

Chapter 3: Testing a Simple Home Page with Unit Tests の締め

以下を学んだ

  • Starting a Django app
  • The Django unit test runner
  • The difference between FTs and unit tests
  • Django URL resolving and urls.py
  • Django view functions, request and response objects And returning basic HTML

正直な話、ゆっくりとぎれとぎれやったため、あまりわかっていない。

しかし、ここで後戻りすると、またループに入るため、そういうことにする。

パダワンパダワン

Column: Useful Commands and Concepts

Running the Django dev server
python manage.py runserver
Running the functional tests
python functional_tests.py
Running the unit tests
python manage.py test

The unit-test/code cycle

  1. Run the unit tests in the terminal. (Unit Testを作成する)
  2. Make a minimal code change in the editor.(テストをパスする最小の変更を行う)
  3. Repeat!(繰り返し!)
パダワンパダワン

冒頭

文句の想定

  • exccesive: 過剰
  • redundant: 冗長
    • There’s duplication between the functional tests and the unit tests.
  • I thought that was a no-no?: それってだめじゃない?
  • too trivial: あまりに些末
  • waste of time
  • "You’re not telling me you actually code like this in real life?": まさか本当にこんなコーディングしてるなんて言わないよね?
  • young grasshopper: 若きキリギリス ← アリとキリギリス?
  • Does all this stuff really have value? : 本当に価値がある?
  • cargo cult?: 新興宗教?
パダワンパダワン

↑ 1h20min もかかって上を読んだ。
途中から諦めて、DeepL で翻訳した。

パダワンパダワン

Programming Is Like Pulling a Bucket of Water Up from a Well

  • Programming は井戸からバケツ(+ひも?)で水を汲み出すようなもの
  • Ultimately, programming is hard. Often, we are smart, so we succeed. TDD is there to help us out when we’re not so smart.
    • 結局の所、プログラミングは難しい。
    • 多くの場合、私達は賢いので成功する。
    • TDD は "私達が賢くないとき" に私達を助けてくれる。
  • Kent Beck (who basically invented TDD)
  • ケント・ベック:TDD の発明者

彼は井戸の例えを使って、以下のことを言っている。

  • 井戸からバケツを使って汲み出すことはできる。
  • しかし次第に疲れる。
  • いつかは手が滑り、バケツを落っことしたり、自分が落ちたりする。
  • TDD はラチェット(一方後にしか回らない滑車, 爪車)のようなもの
  • 進捗を保存し、休憩を取ることができる。
  • その御蔭で 常に賢く(smart) である必要がない。
パダワンパダワン

overdoing: やりすぎ

TDD is a discipline, and that means it’s not something that comes naturally

  • TDD は規律です。それは自然と身につくものではないということを意味しています。

payoffs aren’t immediate

  • すぐには成果が得られない

you have to force yourself to do it in the moment.

  • その瞬間は無理をしてでも行わなければならない。

Testing Goat はそれの象徴です。

you need to be a bit bloody-minded about it.

  • 血の滲むような思いが必要です。
パダワンパダワン

On the Merits of Trivial Tests for Trivial Functions

In the short term it may feel a bit silly to write tests for simple functions and constants.
It’s perfectly possible to imagine still doing “mostly” TDD, but following more relaxed rules where you don’t unit test absolutely everything. But in this book my aim is to demonstrate full, rigorous TDD. Like a kata in a martial art, the idea is to learn the motions in a controlled context, when there is no adversity, so that the techiques are part of your muscle memory. It seems trivial now, because we’ve started with a very simple example. The problem comes when your application gets complex—that’s when you really need your tests. And the danger is that complexity tends to sneak up on you, gradually. You may not notice it happening, but quite soon you’re a boiled frog.
There are two other things to say in favour of tiny, simple tests for simple functions.
Firstly, if they’re really trivial tests, then they won’t take you that long to write them. So stop moaning and just write them already.
Secondly, it’s always good to have a placeholder. Having a test there for a simple func‐ tion means it’s that much less of a psychological barrier to overcome when the simple function gets a tiny bit more complex—perhaps it grows an if. Then a few weeks later it grows a for loop. Before you know it, it’s a recursive metaclass-based polymor‐ phic tree parser factory. But because it’s had tests from the very beginning, adding a new test each time has felt quite natural, and it’s well tested. The alternative involves trying to decide when a function becomes “complicated enough”, which is highly sub‐ jective, but worse, because there’s no placeholder, it seems like that much more effort, and you’re tempted each time to put it off a little longer, and pretty soon—frog soup!
Instead of trying to figure out some hand-wavy subjective rules for when you should write tests, and when you can get away with not bothering, I suggest following the discipline for now—as with any discipline, you have to take the time to learn the rules before you can break them.

簡単な関数の簡単なテストの利点について

短期的には、単純な関数や定数に対してテストを書くのは少し馬鹿げていると感じるかもしれません。
それでも「ほとんど」TDDを行うことは想像に難くありませんが、より緩やかなルールに従って、絶対にすべてをユニットテストするわけではありません。しかし、この本で私が目指すのは、完全で厳密なTDDを実証することです。武術の型のように、逆境がないときに制御された状況で動作を学び、その技術を筋肉の記憶の一部とすることです。非常に単純な例から始めたので、今は些細なことのように思えます。問題は、アプリケーションが複雑になったとき、つまりテストが本当に必要になったときです。そして危険なのは、その複雑さが徐々に忍び寄ってくることです。気づかないうちに、いつの間にかゆでガエルになっているのです。
もうひとつ、単純な関数のテストは小さくシンプルであるべきだという意見もあります。
第一に、本当につまらないテストなら、書くのにそれほど時間はかからないでしょう。だから、文句を言うのはやめて、さっさと書いてしまいましょう。
第二に、プレースホルダーを持つことは常に良いことです。単純な関数に対してテストがあるということは、その単純な関数がほんの少し複雑になったときに克服しなければならない心理的な障壁を減らすことができるということです。そして、数週間後にはforループになる。そしていつの間にか、再帰的なメタクラス・ベースのポリモーフィック・ツリー・パーサ・ファクトリーになっているのです。しかし、最初からテストがあるため、毎回新しいテストを追加するのはごく自然なことであり、テストも十分に行われています。一方、ある関数が「十分に複雑」になったとき、それを判断しようとするのは非常に非効率的ですが、さらに悪いことに、プレースホルダがないため、それだけ多くの労力を要するように思われ、毎回もう少し先延ばしにしたくなり、やがてカエルのスープになってしまうのです。
いつテストを書くべきか、いつなら書かなくて済むか、手探りの主観的なルールを見つけ出そうとするのではなく、とりあえずは規律に従うことをお勧めします。

簡単すぎる関数にテストを設けるメリット

  • 単純なテストならさっさとかけるはず。
  • 複雑になったときにテストを書くのでは、心理的な障壁が大きい。
  • プレースホルダー(本番用に仮置きしたスペース)があるのは非常に良いこと。
  • プレースホルダーがないと、0 からテスト環境を構築することになり、その分テストを書くのに労力がかかるように見えて、先延ばししてしまう。
  • 複雑さに気付く指標を探すのではなく、とりあえず規律に従ってテストを書くことをおすすめする。
パダワンパダワン
  • open up : 開く
  • examine : 調べる

Using Selenium to Test User Interactions

Selenium ドキュメント

  • HTML の各 エレメントに含まれる属性(タグ名、テキストなど色々)を指定するための機能が揃っている。
        # 彼女はページタイトルとヘッダーが To-Do に言及している事に気づいた。
        self.assertIn('To-Do', self.browser.title)
        header_text = self.browser.find_element_by_tag_name('h1').text
        self.assertIn('To-Do', header_text)
        # 早速、To-Do アプリへ項目を入力したくなる。
        inputbox = self.browser.find_element_by_id('id_new_item')
        self.assertEqual(
            inputbox.get_attribute('placeholder'),
            'Enter a to-do item'
        )
  • キーボードのキー入力の指定もできる
        # エンターキーを押すと、ページが更新され、次のようなことが表示される。
        # To-Do リストの項目「1: 孔雀の羽毛を買う」
        inputbox.send_keys(Keys.ENTER)
        time.sleep(1)
パダワンパダワン

The “Don’t Test Constants” Rule, and Templates to the Rescue

  • 定数をテストするのは意味ない。
    • HTML も同じ。
  • Python で HTML を生の文字列として扱うのは良くない。
    • Templates を使う。

Unit tests are really about testing logic, flow control, and configuration. Making assertions about exactly what sequence of characters we have in our HTML strings isn’t doing that.

  • 文字列の並びをアサーションしたりりしない
  • テストロジック、動作のフローコントロール、コンフィグなどを確認する。
パダワンパダワン

Refactoring to Use a Template

The first rule is that you can’t refactor without tests.

  • テストなしにリファクタリングをしてはならない
パダワンパダワン

題名が、オライリーを含んでいるが、オライリーではなく、公式ブログが頒布している無料の本を読んでいるので、タイトルが変わってしまっている。

こういうのは、気づいたときに変えるべきだ。

Misc って結構英語ではその他として、使われているのだな...

パダワンパダワン

Python の環境構築

Docker環境

これで最小限の FastAPI の環境をつくれた。

このAPI上に、機械学習モデルをおいて、それを call すればよい。はず...

このスクラップは2023/03/05にクローズされました