C# 我应该如何测试一个复杂的方法?
我想测试一个复杂的方法, 它接收用户、用户更新的详细信息(密码、恢复问题和电子邮件)和密码 并应检查以下各项:C# 我应该如何测试一个复杂的方法?,c#,unit-testing,C#,Unit Testing,我想测试一个复杂的方法, 它接收用户、用户更新的详细信息(密码、恢复问题和电子邮件)和密码 并应检查以下各项: 确保用户更新了他必须更新的所有字段 独立验证每个字段 确保密码与用户密码匹配(验证) 更新必填字段 如果密码/问题答案已更改,请重新加密敏感数据的特殊密钥(这是一个随机长密钥,用于加密敏感数据,如生日、名字等…密钥还通过密码和问题答案加密保存,而不是现在保存) 主方法使用小方法,即使用其他小方法。 问题是它们都是私有方法,没有理由不使用它们(我不打算在其他任何地方使用它们) 测试这一切
UpdateUserDetails(此用户,
用户详细信息用户详细信息,
字符串密码,
输出错误列表(错误列表)
{
更新操作;
errorList=user.ValidateUserDetails(userDetails,out操作);
if(errorList.IsSuccess()&&actions!=UpdateActions.None)
{
var status=Auth(user.UserId,password);//易于模拟
if(状态:IsSuccess)
{
尝试
{
var newUser=user.UpdateUserDetails(userDetails,actions);
犯罪
返回新用户;
}
抓住
{
回降;
投掷;
}
}
其他的
errorList.Add(AuthErrors.ErrorPassword);
}
返回null;
}
枚举更新操作
{
无=0,
密码=1,
电子邮件=2,
问题=4,
全部=密码、电子邮件和问题
}
编辑:
顺便说一句,我很容易模仿Auth实现,还有DAL实现(向用户发起攻击),其他都是问题
仅就方法内部的方法给出一些观点:
ValidateUserDetails(此用户,
用户详细信息用户详细信息,
out UpdateActions(操作)
{
actions=UpdateActions.None;
ErrorList ErrorList=新的ErrorList()
if(userDetails.password!=null | | user.RequirePasswordUpdate)
{
errorList.AddRange(validatePassword(userDetails.password)//PublicMethod,已经有了测试。
actions.Add(UpdateActions.Password)//ExtensionMethod
}
if(userDetails.email!=null | | user.RequireEmailUpdate)
{
errorList.AddRange(validateEmail(userDetails.Email)//PublicMethod,已经有了测试。
actions.Add(UpdateActions.Email)//ExtensionMethod
}
if(userDetails.Question!=null | | | userDetails.QuestionAnswer | | | user.requirementUpdate)
{
errorList.AddRange(validateQuestion(userDetails.Question,userDetails.QuestionAnswer)//PublicMethod,已经有了测试。
actions.Add(UpdateActions.Question)//ExtensionMethod
}
}
UpdateUserDetails(此用户、UserDetails用户详细信息、UpdateActions操作、字符串oldPassword)
{
if(actions.Has(UpdateActions.UpdatePassword)
user.UpdatePassword(userDetails.password)
...
返回DataAccess.UpdateUser(用户);//易于模拟
}
UpdatePassword(此用户、字符串密码、字符串密码)
{
user.Password=\u ienceryptionmanager.BcryptEncrypt(Password);//易于模拟的加密方法
user.SensKey=\u ienceryptionmanager.DesEncrypt(\u ienceryptionmanager.DesDecrypt(user.SensKey,
旧密码),
密码);
}
非常感谢您的帮助,谢谢大家,
Amir。为了实现这一点,您必须遍历此方法中的所有可用路径。尝试使用一些可用的模拟框架,如rhino Mock。通过使用模拟框架模拟方法的所有输入,以便在内部生成不同的行为。您可以使单元测试项目“参见”通过使用包含这些方法的项目的
AssemblyInfo.cs
中的InternalsVisible
(MSDN文档)属性来创建私有方法
但是,如果需要使用它,这可能表明解决方案中存在架构问题
另一种选择是使用返回指示工作流成功的状态代码的函数(而不是使用上面发布的扩展方法)。然后您可以在单元测试中测试不同的返回值。您应该首先单独对每个功能进行单元测试,因为您的
更新了详细信息()
首先使用ValidateUserDetails()
验证用户详细信息,然后使用Auth()
等检查用户的身份验证
然后,您应该首先创建以下单元测试:
CanValidateUserDetails()
WontaddUserWithErrorPassword()
CanAddUserWithValidPassword()
CanAuthenticateUser()
UpdateUserDetails()
实际执行的操作进行单元测试,即:
user.UpdateUserDetails(userDetails, actions);
通过:
CanUpdateUserDetails()
UpdateUserDetails
是您感兴趣的内容,此方法应首先进行测试。私有部分将作为公共方法测试的附带损害进行测试。最好
ValidateUserDetails(this User user,
UserDetails userDetails,
out UpdateActions actions)
{
actions = UpdateActions.None;
ErrorList<AuthErrors> errorList = new ErrorList<AuthErrors>()
if (userDetails.password != null || user.RequirePasswordUpdate)
{
errorList.AddRange(validatePassword(userDetails.password) // PublicMethod, already, which has tests.
actions.Add(UpdateActions.Password) // ExtensionMethod
}
if (userDetails.email != null || user.RequireEmailUpdate)
{
errorList.AddRange(validateEmail(userDetails.Email) // PublicMethod, already, which has tests.
actions.Add(UpdateActions.Email) // ExtensionMethod
}
if (userDetails.Question != null || userDetails.QuestionAnswer || user.RequireQuestionUpdate)
{
errorList.AddRange(validateQuestion(userDetails.Question, userDetails.QuestionAnswer) // PublicMethod, already, which has tests.
actions.Add(UpdateActions.Question) // ExtensionMethod
}
}
UpdateUserDetails(this User user, UserDetails userDetails, UpdateActions actions, string oldPassword)
{
if (actions.Has(UpdateActions.UpdatePassword)
user.UpdatePassword(userDetails.password)
...
return DataAccess.UpdateUser(user); // Easy to Mock
}
UpdatePassword(this User user, string password, string oldPassword)
{
user.Password = _IEncryptionManager.BcryptEncrypt(password); // easy to mock encryption methods
user.SensKey = _IEncryptionManager.DesEncrypt(_IEncryptionManager.DesDecrypt(user.SensKey,
oldPassword),
password);
}
user.UpdateUserDetails(userDetails, actions);