Я работаю с этим тестом из Mint API Майка Руни :
import copy
import datetime
import json
import unittest
import requests
try:
from mock import patch # Python 2
except ImportError:
from unittest.mock import patch # Python 3
import mintapi
import mintapi.api
accounts_example = [{
"accountName": "Chase Checking",
"lastUpdated": 1401201492000,
"lastUpdatedInString": "25 minutes",
"accountType": "bank",
"currentBalance": 100.12,
}]
class MintApiTests(unittest.TestCase):
@patch.object(mintapi.api, 'get_web_driver')
def test_accounts(self, mock_driver):
token_json = json.dumps({'token': '123'})
mock_driver.return_value.find_element_by_name.return_value.get_attribute.return_value = token_json
accounts_json = json.dumps({'response': {'42': {'response': accounts_example}}})
mock_driver.return_value.request.return_value.text = accounts_json
accounts = mintapi.get_accounts('foo', 'bar')
self.assertFalse('lastUpdatedInDate' in accounts)
self.assertNotEqual(accounts, accounts_example)
accounts_annotated = copy.deepcopy(accounts_example)
for account in accounts_annotated:
account['lastUpdatedInDate'] = (datetime.datetime.fromtimestamp(account['lastUpdated'] / 1000))
self.assertEqual(accounts, accounts_annotated)
# ensure everything is json serializable as this is the command-line
# behavior.
mintapi.print_accounts(accounts)
def test_chrome_driver_links(self):
for platform in mintapi.api.CHROME_ZIP_TYPES:
zip_type = mintapi.api.CHROME_ZIP_TYPES.get(platform)
zip_file_url = mintapi.api.CHROME_DRIVER_BASE_URL % (mintapi.api.CHROME_DRIVER_VERSION, zip_type)
request = requests.get(zip_file_url)
self.assertEqual(request.status_code, 200)
def test_parse_float(self):
answer = mintapi.api.parse_float('10%')
self.assertEqual(answer, float(10))
answer = mintapi.api.parse_float('$10')
self.assertEqual(answer, float(10))
answer = mintapi.api.parse_float('0.00%')
self.assertEqual(answer, float(0))
get_web_driver
первоначально вернул один параметр.
Я добавил дополнительный параметр в get_web_driver
, поэтому строка возврата выглядит следующим образом:
return driver, status_message
вместо
return driver
Реальный код работает нормально; У меня проблемы с тем, чтобы Трэвис сдал тесты. Я попытался добавить дополнительный параметр mocked различными способами, но тесты не дали результатов:
ValueError: not enough values to unpack (expected 2, got 0)
У меня есть два вопроса:
- Почему не проверяется функция mocked уже возвращает один параметр?
- Как добавить дополнительный параметр для прохождения теста * & ^% $% ^?
спасибо за любую помощь, которую вы можете мне дать.
Вот трассировка стека:
Error
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
yield
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 628, in run
testMethod()
File "/usr/local/lib/python3.7/site-packages/mock/mock.py", line 1330, in patched
return func(*args, **keywargs)
File "/Users/jrt/Documents/projects/mintapi/mintapi/tests.py", line 34, in test_accounts
accounts = mintapi.get_accounts('foo', 'bar')
File "/Users/jrt/Documents/projects/mintapi/mintapi/api.py", line 973, in get_accounts
mint = Mint.create(email, password)
File "/Users/jrt/Documents/projects/mintapi/mintapi/api.py", line 377, in create
return Mint(email, password, **opts)
File "/Users/jrt/Documents/projects/mintapi/mintapi/api.py", line 373, in __init__
wait_for_sync_timeout=wait_for_sync_timeout)
File "/Users/jrt/Documents/projects/mintapi/mintapi/api.py", line 461, in login_and_get_token
wait_for_sync_timeout=wait_for_sync_timeout)
ValueError: not enough values to unpack (expected 2, got 0)
Вот новая get_web_driver
, которая возвращает и драйвер, и переменную status_message (изначально она только возвращала драйвер):
def get_web_driver(email, password, headless=False, mfa_method=None,
mfa_input_callback=None, wait_for_sync=True,
wait_for_sync_timeout=5 * 60,
session_path=None, imap_account=None, imap_password=None,
imap_server=None, imap_folder="INBOX"):
if headless and mfa_method is None:
warnings.warn("Using headless mode without specifying an MFA method"
"is unlikely to lead to a successful login. Defaulting --mfa-method=sms")
mfa_method = "sms"
zip_type = ""
executable_path = os.getcwd() + os.path.sep + 'chromedriver'
if _platform in ['win32', 'win64']:
executable_path += '.exe'
zip_type = CHROME_ZIP_TYPES.get(_platform)
if not os.path.exists(executable_path):
zip_file_url = CHROME_DRIVER_BASE_URL % (CHROME_DRIVER_VERSION, zip_type)
request = requests.get(zip_file_url)
if request.status_code != 200:
raise RuntimeError('Error finding chromedriver at %r, status = %d' %
(zip_file_url, request.status_code))
zip_file = zipfile.ZipFile(io.BytesIO(request.content))
zip_file.extractall()
os.chmod(executable_path, 0o755)
chrome_options = ChromeOptions()
if headless:
chrome_options.add_argument('headless')
chrome_options.add_argument('no-sandbox')
chrome_options.add_argument('disable-dev-shm-usage')
chrome_options.add_argument('disable-gpu')
# chrome_options.add_argument("--window-size=1920x1080")
if session_path is not None:
chrome_options.add_argument("user-data-dir=%s" % session_path)
driver = Chrome(chrome_options=chrome_options, executable_path="%s" % executable_path)
driver.get("https://www.mint.com")
driver.implicitly_wait(20) # seconds
try:
element = driver.find_element_by_link_text("Sign in")
except NoSuchElementException:
# when user has cookies, a slightly different front page appears
driver.implicitly_wait(0) # seconds
element = driver.find_element_by_link_text("Sign in")
driver.implicitly_wait(20) # seconds
element.click()
time.sleep(1)
email_input = driver.find_element_by_id("ius-userid")
# It's possible that the user clicked "remember me" at some point, causing
# the email to already be present. If anything is in the input, clear it
# and use the provided email, just to be safe.
# email_input.setAttribute("value", "")
email_input.clear()
email_input.send_keys(email)
driver.find_element_by_id("ius-password").send_keys(password)
driver.find_element_by_id("ius-sign-in-submit-btn").submit()
# Wait until logged in, just in case we need to deal with MFA.
while not driver.current_url.startswith(
'https://mint.intuit.com/overview.event'):
# An implicitly_wait is also necessary here to avoid getting stuck on
# find_element_by_id while the page is still in transition.
driver.implicitly_wait(1)
time.sleep(1)
# bypass "Let's add your current mobile number" interstitial page
try:
skip_for_now = driver.find_element_by_id('ius-verified-user-update-btn-skip')
skip_for_now.click()
except (NoSuchElementException, StaleElementReferenceException, ElementNotVisibleException):
pass
driver.implicitly_wait(1) # seconds
try:
if mfa_method == 'soft-token':
mfa_token_input = driver.find_element_by_id('ius-mfa-soft-token')
mfa_code = (mfa_input_callback or input)("Please enter your 6-digit MFA code: ")
mfa_token_input.send_keys(mfa_code)
mfa_token_submit = driver.find_element_by_id('ius-mfa-soft-token-submit-btn')
mfa_token_submit.click()
else:
driver.find_element_by_id('ius-mfa-options-form')
try:
mfa_method_option = driver.find_element_by_id('ius-mfa-option-{}'.format(mfa_method))
mfa_method_option.click()
mfa_method_submit = driver.find_element_by_id("ius-mfa-options-submit-btn")
mfa_method_submit.click()
if mfa_method == 'email' and imap_account:
mfa_code = get_email_code(imap_account, imap_password, imap_server, imap_folder=imap_folder)
else:
mfa_code = (mfa_input_callback or input)("Please enter your 6-digit MFA code: ")
mfa_code_input = driver.find_element_by_id("ius-mfa-confirm-code")
mfa_code_input.send_keys(mfa_code)
mfa_code_submit = driver.find_element_by_id("ius-mfa-otp-submit-btn")
mfa_code_submit.click()
except Exception: # if anything goes wrong for any reason, give up on MFA
mfa_method = None
warnings.warn("Giving up on handling MFA. Please complete "
"the MFA process manually in the browser.")
except NoSuchElementException:
pass
finally:
driver.implicitly_wait(20) # seconds
# Wait until the overview page has actually loaded, and if wait_for_sync==True, sync has completed.
status_message = None
if wait_for_sync:
try:
# Status message might not be present straight away. Seems to be due
# to dynamic content (client side rendering).
status_message = WebDriverWait(driver, 30).until(
expected_conditions.visibility_of_element_located(
(By.CSS_SELECTOR, ".SummaryView .message")))
WebDriverWait(driver, wait_for_sync_timeout).until(
lambda x: "Account refresh complete" in status_message.get_attribute('innerHTML')
)
except (TimeoutException, StaleElementReferenceException):
status_message = "Mint sync apparently incomplete after timeout. Data retrieved may not be current."
warnings.warn(status_message)
else:
driver.find_element_by_id("transaction")
if status_message is not None and isinstance(status_message, WebElement):
status_message = status_message.text
return driver, status_message