[Python]肥満度判定プログラムを作ってテストしてみる。
肥満度の指標を示すBMIを求めて肥満度を判定するプログラムを作ります。また、作ったプログラムが思い描いた通りに動くか事前にdoctestモジュールを用いたテストをします。
1.肥満度を判定するプログラム
肥満度は身長[m]と体重[kg]からBMIを計算し、その値から定められた条件によって判定できることができます。これより、以下の2点の機能を持つ関数を作成します。
・身長と体重からBMIを計算する
・BMIから肥満度を判定する
1-1.身長と体重からBMIを計算する
身長と体重2つの引数を受け取りBMIを返す関数を作成します。
身長は[m]で計算されますが、ここで受け取る身長の単位は[cm]とします。
なぜなら、よく人に身長を「身長何メートル?」と聞く事がほぼないからです。
def calc_bmi(height, weight):
"""Calc bmi
>>> print(calc_bmi(175, 60))
19.6
"""
height_to_meter = height / 100
bmi = weight / height_to_meter ** 2
return round(bmi, 1)
関数内のドキュメンテーション文字列は後のテストで使用します。
1-2.BMIから肥満度を判定する
BMIを引数に受け取り、定められた条件によって肥満度を判定する関数を作成します。ここで指す定められた条件は、日本肥満学会の定める条件に基づきます。
ところで、日本語で肥満度を判定するのも味気ないと思ったので言語別に出力できるように、新たに言語を設定する変数も追加してみました。
def judge_obesity(bmi, lang):
"""Judge obesity by bmi and output message by choiced language
>>> print(judge_obesity(19.6, 0))
標準
>>> print(judge_obesity(19.6, 1))
NormalWeight
>>> print(judge_obesity(19.6, 2))
標準
"""
ja_message = ["やせすぎ", "標準", "ちょっとぽっちゃり", "ぽっちゃり"]
en_message = ["UnderWeight", "NormalWeight", "OverWeight", "Obese"]
if lang == 0:
output_lang = ja_message.copy()
elif lang == 1:
output_lang = en_message.copy()
else:
output_lang = ja_message.copy()
#BMIの判定を入力された数値から判定
if bmi < 18.5:
return output_lang[0]
elif bmi >= 18.5 and bmi < 25:
return output_lang[1]
elif bmi >= 25 and bmi < 30:
return output_lang[2]
elif bmi >= 30:
return output_lang[3]
上記1-1と同様に関数内のドキュメンテーション文字列は後のテストで使用します。
2.doctestモジュールを使ったテスト
作った関数が思い通りに動くかどうかをテストしてみます。
doctestモジュールをインポートして使用する関数はtestmod()です。
import doctest
def calc_bmi(height, weight):
"""Calc bmi
>>> print(calc_bmi(175, 60))
19.6
"""
height_to_meter = height / 100
bmi = weight / height_to_meter ** 2
return round(bmi, 1)
def judge_obesity(bmi, lang):
"""Judge obesity by bmi and output message by choiced language
>>> print(judge_obesity(19.6, 0))
標準
>>> print(judge_obesity(19.6, 1))
NormalWeight
>>> print(judge_obesity(19.6, 2))
標準
"""
ja_message = ["やせすぎ", "標準", "ちょっとぽっちゃり", "ぽっちゃり"]
en_message = ["UnderWeight", "NormalWeight", "OverWeight", "Obese"]
if lang == 0:
output_lang = ja_message.copy()
elif lang == 1:
output_lang = en_message.copy()
else:
output_lang = ja_message.copy()
#BMIの判定を入力された数値から判定
if bmi < 18.5:
return output_lang[0]
elif bmi >= 18.5 and bmi < 25:
return output_lang[1]
elif bmi >= 25 and bmi < 30:
return output_lang[2]
elif bmi >= 30:
return output_lang[3]
doctest.testmod()
事前に関数内で記述したドキュメンテーション文字列を元にテストをしてくれます。実行結果は以下になります。ファイル名はcalc_bmi_test.pyとしています。
NobitaMacBook-puro:practice nobita$ python3 bmi_calc_test.py
NobitaMacBook-puro:practice nobita$
異常がなければ、何も出力されません。何が起きているか詳細なログを出力したい場合はこれにvオプションを加えます。
NobitaMacBook-puro:practice nobita$ python3 bmi_calc_test.py -v
Trying:
print(calc_bmi(175, 60))
Expecting:
19.6
ok
Trying:
print(judge_obesity(19.6, 0))
Expecting:
標準
ok
Trying:
print(judge_obesity(19.6, 1))
Expecting:
NormalWeight
ok
Trying:
print(judge_obesity(19.6, 2))
Expecting:
標準
ok
1 items had no tests:
__main__
2 items passed all tests:
1 tests in __main__.calc_bmi
3 tests in __main__.judge_obesity
4 tests in 3 items.
4 passed and 0 failed.
Test passed.
わざと間違ったケースを書いてみます。judge_obesityのNormalWeightで出力されるところをOverWeightに書き換えます。すると以下の結果が出力されます。
**********************************************************************
File "bmi_calc_test.py", line 16, in __main__.judge_obesity
Failed example:
print(judge_obesity(19.6, 1))
Expected:
OverlWeight <==テストで書いた予想される値
Got:
NormalWeight <==実際に出力される値
**********************************************************************
1 items had failures:
1 of 3 in __main__.judge_obesity
***Test Failed*** 1 failures.
3.完成させる
完成させてみます。ゴールはテストケースが正常に通った場合、ユーザーに入力を求めてBMIを判別ができる事です。
import doctest
def calc_bmi(height, weight):
"""Calc bmi
>>> print(calc_bmi(175, 60))
19.6
"""
height_to_meter = height / 100
bmi = weight / height_to_meter ** 2
return round(bmi, 1)
def judge_obesity(bmi, lang):
"""Judge obesity by bmi and output message by choiced language
>>> print(judge_obesity(19.6, 0))
標準
>>> print(judge_obesity(19.6, 1))
NormalWeight
>>> print(judge_obesity(19.6, 2))
標準
"""
ja_message = ["やせすぎ", "標準", "ちょっとぽっちゃり", "ぽっちゃり"]
en_message = ["UnderWeight", "NormalWeight", "OverWeight", "Obese"]
if lang == 0:
output_lang = ja_message.copy()
elif lang == 1:
output_lang = en_message.copy()
else:
output_lang = ja_message.copy()
#BMIの判定を入力された数値から判定
if bmi < 18.5:
return output_lang[0]
elif bmi >= 18.5 and bmi < 25:
return output_lang[1]
elif bmi >= 25 and bmi < 30:
return output_lang[2]
elif bmi >= 30:
return output_lang[3]
if __name__ == "__main__":
#テスト結果をresult変数に代入
result = doctest.testmod()
#result変数に格納されているタプルをそれぞれアンパック
failure_count, test_count = result
if failure_count != 0:
print(result)
else:
lang_setting = int(input("Chose language[0:日本語/1:English]:"))
height = int(input("Enter your height[cm]:"))
weight = int(input("Enter your weight[kg]:"))
bmi = calc_bmi(height, weight)
status = judge_obesity(bmi, lang_setting)
context = "BMI:{0} STATUS:{1}".format(bmi, status)
print(context)
4.実行結果
Chose language[0:日本語/1:English]:1
Enter your height[cm]:175
Enter your weight[kg]:60
BMI:19.6 STATUS:NormalWeight