所以我撰寫了一個 python 程式,提示用戶輸入字母 A 或 B,然后輸入一個數字來確定他們需要多長時間才能累積 1 000 000。我需要有關如何為函式 def profile、option_check 撰寫測驗的幫助(f) 全部使用 PYTEST。
`
import math
import sys
# Global variables
s = 1000000 # final amount
r = float(11.88/100) # convert s&p500 annual return to effective monthly rate
i = float(r / 12) # effective rate
def main():
x = input('Do you want to:\n (A): calculate how long it will take to save your first million investing a fixed amount in the S&P500 monthly?\n OR \n (B): Calculate how much you should save in the S&P500 per month to reach 1 000 000 within your time period?\n Type A or B: ')
letter = profile(x)
result = option_check(letter)
print(result)
sys.exit()
# do users want how long it will take or how much to save within a period
def profile(x):
while True:
try:
letter = x.upper()
if letter == 'A' or letter == 'B':
return letter
else:
main()
except ValueError:
print('INVALID ! Please enter: A or B')
def option_check(f):
if f == 'A':
pay_periods, amount = option_a()
years, months = time(pay_periods)
result = f"It will take {years} years and {months} months investing {amount} in the S&P500 to reach 1000 000"
return result
if f == 'B':
amount, time_frame = option_b()
result = f'You will reach 1 000 000 in {time_frame} years by investing {amount} in the S&P500 Monthly'
return result
def option_a():
# error check for ints
while True:
try:
# monthly amount
p = int(input('How much do you plan on saving in the S&P500 per month?\n'))
# calculate years
top = 1 - (s * (1 - (1 i)) / p)
periods = math.log(top) / math.log(1 i)
return periods, p
except:
print('Enter valid number\n')
def time(x):
years = math.floor(x / 12)
months = math.floor(12 * (x / 12 - math.floor(years)))
return years, months
def option_b():
while True:
try:
time_frame = int(input('What time frame do you have to reached 1 000 000 in years?\n'))
# calculationg p: the monthly payment needed
periods = time_frame * 12
top = s - s * (1 i)
bottom = 1 - (1 i ) ** periods
amount = round(top / bottom , 2)
return amount, time_frame
except:
print('Please Enter VALID NUMBER...\n')
if __name__ == '__main__':
main()
`
from forecast import option_check, time, profile
def main():
test_time()
test_option_check()
def test_time():
assert time(12) == 1
def test_option_check():
assert option_check('?')
def test_profile():
assert profile('A')
if __name__ == '__main__':
main()
由于函式回傳超過 1 個值,我將如何測驗?
uj5u.com熱心網友回復:
嗨 check123,歡迎來到 StackOverflow。您要完成的是對代碼進行單元測驗。這通常意味著代碼的某些部分需要修補或模擬,您的情況也不例外。
首先,讓我們看一下 forecast.py 檔案。我添加了一些行內注釋并稍微更改了代碼。
預測.py
import math
import sys
# Global variables
s = 1000000 # final amount
r = float(11.88/100) # convert s&p500 annual return to effective monthly rate
i = float(r / 12) # effective rate
def main():
x = input('Do you want to:\n (A): calculate how long it will take to save your first million investing a fixed amount in the S&P500 monthly?\n OR \n (B): Calculate how much you should save in the S&P500 per month to reach 1 000 000 within your time period?\n Type A or B: ')
letter = profile(x)
result = option_check(letter)
print(result)
sys.exit()
# do users want how long it will take or how much to save within a period
def profile(x):
try:
letter = x.upper()
# This if else will never raise a ValueError because if its not A or B the else just re-runs main()
# To raise a ValueError if A or B not given, you need to raise the error within the else
# The while True will also cause an infinite error loop, so remove that
if letter == 'A' or letter == 'B':
return letter
else:
raise ValueError()
except ValueError:
print('INVALID ! Please enter: A or B')
def option_check(f):
if f == 'A':
pay_periods, amount = option_a()
years, months = time(pay_periods)
result = f"It will take {years} years and {months} months investing {amount} in the S&P500 to reach 1000 000"
return result
if f == 'B':
amount, time_frame = option_b()
result = f'You will reach 1 000 000 in {time_frame} years by investing {amount} in the S&P500 Monthly'
return result
def option_a():
# error check for ints
while True:
try:
# monthly amount
p = int(input('How much do you plan on saving in the S&P500 per month?\n'))
# calculate years
top = 1 - (s * (1 - (1 i)) / p)
periods = math.log(top) / math.log(1 i)
return periods, p
# Try to be specific with error handling when possible
except ValueError:
print('Enter valid number\n')
def time(x):
years = math.floor(x / 12)
months = math.floor(12 * (x / 12 - math.floor(years)))
return years, months
def option_b():
while True:
try:
time_frame = int(input('What time frame do you have to reached 1 000 000 in years?\n'))
# calculating p: the monthly payment needed
periods = time_frame * 12
top = s - s * (1 i)
bottom = 1 - (1 i) ** periods
amount = round(top / bottom, 2)
return amount, time_frame
# Try to be specific with error handling when possible
except ValueError:
print('Please Enter VALID NUMBER...\n')
if __name__ == '__main__':
main()
現在讓我們看一下測驗檔案:
測驗.py
import pytest
from forecast import option_check, time, profile
from unittest.mock import patch
def test_time():
# Since time() returns a tuple we can assign a var to each member of the returned tuple
# This will allow us to assert individually on those vars for the correct answers
years, months = time(12)
assert years == 1
assert months == 0
# The mark parametrize will allow us to test multiple different inputs in one test function
@pytest.mark.parametrize("option", ["A", "B"])
def test_option_check(option):
# Need to patch the input message for testing purposes
# Then we can run the code with the return_value of 1 as the user input
with patch("builtins.input", return_value=1):
result = option_check(option)
# This assertion allows us to assert on the correct message
# given the option we passed in from the parametrize decorator
assert result == ("It will take 77 years and 9 months investing 1 in the S&P500 to reach 1000 000" if option == "A" else "You will reach 1 000 000 in 1 years by investing 78892.66 in the S&P500 Monthly")
@pytest.mark.parametrize("letter", ["A", "a", "B", "b"])
def test_profile(letter):
if letter in ["A", "a"]:
result = profile(letter)
assert result == "A"
elif letter in ["B", "b"]:
result = profile(letter)
assert result == "B"
這里要注意的主要部分是 pytest.mark.parametrize 和 patch()。
鏈接:引數化:https ://docs.pytest.org/en/7.1.x/example/parametrize.html 補丁:https ://docs.python.org/3/library/unittest.mock.html
上面的兩個鏈接都將有助于解釋它們的作用。但總體思路是:
引數化 --> 這允許我們為給定的測驗函式構建引數,這將使用給定的引數對測驗函式進行引數化。每個引數都將構建該測驗函式的一個新實體,允許我們測驗許多引數而無需復制測驗函式。
模擬(特別是 Patch()) --> 這允許我們使用回傳值或副作用來修補代碼實體。這些庫有很多,所以我建議查看提供的鏈接。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/523258.html
上一篇:如何在顫振中從dartz包中為Either<>撰寫測驗
下一篇:如何在單元測驗中模擬可觀察變數?
