[英]Robotframework test cases , how topn write a test cases for this scenaries
[英]How to write registering account test cases?
这是此帖子的后续问题
在对我的代码进行了调整之后,下面是我的完整工作代码。
但是,我有一些问题和疑问:
这是我的测试,但是createAccount()没有参数,因此如何向其添加输入以进行测试?
def test_canCreateAccount(ctrl):
#valid email and password
email = 'hello@gmail.com'
password1 = 'beautiful'
password2 = 'beautiful'
account = ctrl.createAccount()
assert account.email == email
assert account.password == password1
编写接受输入并返回结果的函数。 没有副作用。
不要将异常用于控制流。
**还是我误会了某些东西?
无情地削减职能,直到他们做一件事。
那么,为什么createAccount()做2件事? 它从用户输入中获取价值,然后进行验证
class CreateAccountFailed(Exception):
pass
class PassNotValid(CreateAccountFailed):
pass
class PassNotMatch(CreateAccountFailed):
pass
class EmailNotOK(CreateAccountFailed):
pass
class RegisterUI:
def getEmail(self):
return input("Please type an your email:")
def getPassword1(self):
return input("Please type a password:")
def getPassword2(self):
return input("Please confirm your password:")
def getSecKey(self):
return input("Please type your security keyword:")
def printMessage(self, message):
print(message)
class RegisterController:
def __init__(self, view):
self.view = view
def displaymessage(self, message):
self.view.printMessage(message)
def ValidateEmail(self, email):
email_obj = Email(email)
return email_obj.isValidEmail() and not accounts.isDuplicate(email)
def ValidatePassword(self, password):
return Password.isValidPassword(password)
def CheckPasswordMatch(self, password1, password2):
return Password.isMatch(password1, password2)
def makeAccount(self, email, password, seckey):
return Account(Email(email), Password(password), seckey)
def createAccount(self):
email = self.view.getEmail()
if not self.ValidateEmail(email):
raise EmailNotOK("Duplicate or incorrect format")
password1 = self.view.getPassword1()
if not self.ValidatePassword(password1):
raise PassNotValid("Password is not valid")
password2 = self.view.getPassword2()
if not self.CheckPasswordMatch(password1, password2):
raise PassNotMatch("Passwords don't match")
return self.makeAccount(email, password1, self.view.getSecKey())
def tryCreateAccount(self):
try:
account = self.createAccount()
self.displaymessage("Account was created successfully")
return account
except CreateAccountFailed as e:
self.displaymessage(str(e))
class Register(Option):
def execute(self):
view = RegisterUI()
controller_one = RegisterController(view)
controller_one.tryCreateAccount()
注意: 另一个答案中的代码不是最好的代码,但是它对我们从何处开始进行了巨大的改进。 重构的一部分是知道什么时候足够好。 请记住,阅读本文时,可以进行更多的改进,但是可以实现createAccount()
可测试的目标。
- 这是我的测试,但是createAccount()没有参数,那么如何为测试添加输入呢?
createAccount
从self.view
获取其信息。 那是一个RegisterUI
对象。 RegisterUI
的方法是交互式的,这使得它们很难在测试中使用。
幸运的是,我们可以将我们喜欢的任何视图传递给RegisterController
。 我们不测试RegisterUI
,它应该具有自己的测试,就像RegisterController
如何使用RegisterUI
。 因此,我们将创建一个RegisterUI
版本,仅用于测试和使用。
我们可以制作一个响应RegisterUI
方法的Mock对象 。
from unittest.mock import Mock
attrs = {
'getEmail.return_value': email,
'getPassword1.return_value': password1,
'getPassword2.return_value': password2,
'getSecKey'.return_value': seckey
}
mock_view = Mock(**attrs)
mock_view.getEmail()
将返回email
,依此类推。 使用它作为控制器的视图。
ctrl = RegisterController(mock_view)
account = ctrl.createAccount()
assert account.email == email
assert account.password == password1
assert account.seckey == seckey
另外,您可以编写RegisterUI
的子类以进行测试,该子类在构造函数中使用其属性,并覆盖getEmail()
和friends以返回它们。 与模拟游戏类似,但更有条理。
- createAccount()是否违反[编写接受输入并返回结果的函数。 没有副作用。]? 它没有接受输入的参数。
从技术上说是的,但这是一个经验法则。 您可以传递view
而不是使用self.view
,但是控制器的重点是弥合视图和模型之间的差距。 可以访问UI是适当的。
createAccount()
是一个集成函数。 它封装了使用UI中的信息创建帐户的过程; 无需了解用户界面的详细信息,也无需帐户。 很好 您可以更改帐户创建过程,所有调用createAccount()
仍然可以使用。
- createAccount()中的“ if”语句是控制流吗? 如果是,[这是否在控制流中使用异常?]
是的, if
是控制流程。 但是createAccount()
并未将异常用于控制流。
例外是例外情况。 open
打开一个文件。 如果无法打开文件,则会出现异常。 createAccount()
创建一个帐户。 如果无法创建例外帐户,则抛出异常。
将此与isEmailValid(email)
类的函数进行对比。 这是在询问电子邮件是否有效。 使用异常指示无效的电子邮件是不合适的; 完全预期isEmailValid(email)
将收到无效的电子邮件。 无效的电子邮件是isEmailValid
的正常情况。 相反,它应该返回一个简单的布尔值。
但是, isEmailValid(email)
可能使用异常来指示为什么电子邮件无效。 例如,它可能抛出EmailIsDuplicate
表示重复,而EmailIsInvalid
表示这是格式问题。
def ValidateEmail(self, email):
email_obj = Email(email)
if !accounts.isDuplicate(email):
raise EmailIsDuplicate()
if !email_obj.isValidEmail():
raise EmailIsInvalid()
return true
然后,调用者可以使用异常来显示适当的错误。
try:
self.ValidateEmail(email)
except EmailIsDuplicate
self.displaymessage("That email is already registered.")
except EmailIsInvalid
self.displaymessage("The email is not formatted correctly.")
createAccount()
在做什么。
- [如果我应该“无情地削减函数,直到它们做一件事”,为什么] createAccount()做2件事? 它从用户输入中获取价值,然后进行验证。
从外部的角度来看,它做一件事:它负责根据用户输入创建帐户。 确切的说,这是一个黑匣子。 该信息隐藏意味着,如果创建帐户的工作方式的详细信息发生更改,则对程序其余部分的影响将受到限制。
如果稍后它决定一个帐户需要一个名称,则可以将该名称添加到createAccount()
(和RegisterUI.getName
)中,而无需更改其接口。
- 我想[作为有效电子邮件的用户最多3次]。 之后,应用程序引发异常。 如何进行简单测试?
昨天在处理您的代码时,我没有意识到self.view.getEmail()
是交互式的! 那解释了无限循环。 我不明白。
我们将添加另一种方法来封装请求有效的电子邮件。
def AskForValidEmail(self):
for x in range(0, 3):
email = self.view.getEmail()
if self.ValidateEmail(email):
return email
else:
self.displaymessage("Email was invalid or a duplicate, please try again")
raise EmailNotOK
同样,我们将折叠询问密码并将其验证为一种方法。 现在,我了解了while 1
用途是什么,您想问一下,直到他们给您提供有效的密码。
def AskForValidPassword(self):
while 1:
password1 = self.view.getPassword1()
password2 = self.view.getPassowrd2()
if !Password.isMatch(password1, password2):
self.displaymessage("The passwords do not match")
elif !Password.isValidPassword(password):
self.displaymessage("The password is invalid")
else
return password1
然后createAccount()
调用它们,使其更纤薄。
def createAccount(self):
email = self.AskForValidEmail()
password = self.AskForValidPassword()
return self.makeAccount(email, password1, self.view.getSecKey())
要测试AskForValidEmail
您可以制作一个更好的RegisterUI
模拟。 代替getEmail
仅返回字符串,它可以在前两个调用中返回无效的电子邮件,而在第三个调用中返回有效的电子邮件。
这是上述Schwern答案的补充(添加更多信息)。 我们需要确定测试的目的。 我认为以下两个原因,每个原因导致使用相同策略实现模拟。
该策略是要有一个全局数组(如果有要模拟的对象,请改用对象的属性)以跟踪调用模拟的次数。 以下是建议。
count_try = [
'mock_3_failed': 0,
'mock_3rd_good': 0,
]
def mock_3_failed():
values = ['1st', '2nd', '3rd']
current_count = count_try['mock_3_failed']
result = values[current_count]
# When count reaches len(values) - 1 (2 for 3 element list), reset to 0
count_try['mock_3_failed'] = (current_count + 1
) if current_count < len(values) - 1 else 0
return result
def mock_3rd_good():
values = ['1st', '2nd', 'third@company.com']
current_count = count_try['mock_3rd_good']
result = values[current_count]
count_try['mock_3_failed'] = (current_count + 1
) if current_count < len(values) - 1 else 0
return result
之后,您可以拥有2个测试功能。 一个使用了mock_3_failed,然后断言抛出了异常。 另一个使用mock_3rd_good然后断言返回了预期的结果。
另一个补充是重构“提升/尝试”控制流。 当前,我们将逻辑知识存储在两个位置:ValidateEmail函数用于检查,AskForValidEmail用于报告错误。 相反,我们只能将其重构到一个位置:ValidateEmail函数。 这将有助于将来的代码更改。
def ValidateEmail(self, email):
email_obj = Email(email)
if !accounts.isDuplicate(email):
raise EmailNotOK("That email is already registered.")
if !email_obj.isValidEmail():
raise EmailNotOK("The email is not formatted correctly.")
return true
def AskForValidEmail(self):
MAX_TRY = 3
for x in range(0, MAX_TRY):
email = self.view.getEmail()
try:
self.ValidateEmail(email)
except EmailNotOK as e:
self.displaymessage(str(e))
raise EmailNotOK('Reached max number of trying (%d).')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.