TheGameをつくる②~Numberクラスの実装_インスタンス生成~
目次
前回のあらすじ
とりあえず開発環境だけできた。
開発環境もう少し見直し
githubにpushしたタイミングでテストを通るようにして、Lintを実行できるようにしました。
name: Python application on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Set up Python 3.7 uses: actions/setup-python@v1 with: python-version: 3.7 - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Lint with flake8 run: | pip install flake8 # stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | pip install -e ./src/BL/ pip install pytest pytest
ウィザードに従ってポチポチするだけでできるから素敵。
pip install -e ./src/BL/
ここだけ、pytest実行できるように自作のパッケージを読み込むようにした。同じようにDockerfileもBuildで読むように
#pytest setup
RUN pip install -e ./src/BL/
を追記。
これで、
・githubに上げればGitActionが勝手に環境を作ってテストをしてくれる。
・Dockerでコンテナ立ち上げればパッケージ読み込んだ状態でそく「pytest」をぶち込める環境になる。
が達成できている。
コードメトリクスも収集しといたほうがいいかなぁ。radon放り込むだけだろうから。
ということでRadonうめこみ
末尾に以下を追加した
- name: Code Metorix run: | pip install radon radon cc -s -e "*test/*" . radon mi -s -e "*test/*" .
結果。
gyazo.com
いいでしょう。
Numberクラスのインスタンス
単に数値を渡して、数字を返すだけ。後々Numberにはいろいろ機能を付加しないといけなくなる。
※TheGameは11,22とかぞろ目に意味があったり、僕のかった悪魔の方はほかにも効果があったりする。
ということも踏まえて、単に数値で持つよりクラス化したほうが良さそうなのでクラス化した。
モジュールのイメージはこんな感じ。
gyazo.com
RandomNumber.pyはモジュール名としてふさわしくないと思う。そのうち直すけどいったんこれでいく。
※乱数生成しなきゃ。ってのがずっと頭にあるせいでこんなパッケージ名になってしまった。
※BLはビジネスロジック
先にテストを書いてからコードを作るよ
テストの方の階層はこんな感じ。
gyazo.com
test_RandomNumber.py
#third import pytest #user from BL_main.RandomNumber import * def test_NumberClass_InvalidException_underNumber(): ''' Test argument. under number. ''' with pytest.raises(InvalidArgumentExceptionOfNumber): Number.create(1) Number.create(2) def test_NumberClass_InvalidException_overNumber(): ''' Test argument. over number. ''' with pytest.raises(InvalidArgumentExceptionOfNumber): Number.create(100) Number.create(99) def test_NumberClass_CreateTargetNumber(): ''' Test NumberClass initialize. ''' actual = Number.create(3) assert actual.value == 3 actual2 = Number.create(3) assert actual == actual2 actual3 = Number.create(4) assert actual != actual3
とりあえず「2~99」の数値しか作れないので、OverとUnderのテスト。
加えて、適当な数字を作って同値比較できるかどうか。までを書いた。
実装はこんな感じ。
RandomNumebr.py
class Number: ''' Number Class. ''' def create(number): ''' Number Class Basic Factory. ''' if (number > 99) : raise InvalidArgumentExceptionOfNumber("over number") if (number < 2): raise InvalidArgumentExceptionOfNumber("under number") return Number(number) def __init__(self, number): ''' Constractor. ''' self.value = number def __eq__(self, other): ''' Override Equals. ''' if not isinstance(other, Number): return NotImplemented return self.value == other.value class InvalidArgumentExceptionOfNumber(Exception): pass
ちょっと前まで、pythonの階層とかファイルわけどうしたらいいだろうか。と悩んでたけど、
「.py」は等しくモジュール。ということで腑に落ちた。ひたすらここにクラス書いて問題なさそう。ということでここが膨らんでいくと思われる。
マジックナンバーもあるし、微妙だけどとりあえずこれでいいんじゃなかろう?かかかのか。
Equalsはともかくとして、ゲームとして大小比較はデリケートなところなので(つまり、これから出そうとする数字が今より大きいか小さいか)そこはいったんおきにしておいた。
ゲームのコントロール側を実装するときにまた出てくると思う。
次回の予定
乱数。乱数つくらないとね。あとNumber「s」クラス。コレクションしとかないとめんどくさそう。
手札、山札、コレクション。うーん。この辺ができたらようやくゲームメインかな。