标题不是很具体,但让我们用例子。我们有ASP.NET MVC操作代码:
[HttpPost]
[ExportModelStateToTempData]
public RedirectToRouteResult ChangePassword(int id, UserChangePasswordVM changePassword)
{
if (ModelState.IsValid)
{
var user = _userService.GetUserByID(id);
//Checking old password. Administrators can change password of every user,
//providing his password instead of user's old password.
bool oldPasswordIsCorrect = _loginService.CheckPassword(
CurrentPrincipal.IsInRole(CTRoles.IsAdmin) ?
CurrentPrincipal.User.UserName : user.UserName,
changePassword.OldPassword);
if (oldPasswordIsCorrect)
{
TempDataWrapper.Message =
_userService.ChangePassword(user.UserName, changePassword.NewPassword) ?
CTRes.PasswordChangedSuccessfully : CTRes.ErrorProcessingRequest;
}
else
{
ModelStateWrapper.AddModelError("ChangePassword.OldPassword",
CTRes.CurrentPasswordIsNotValid);
}
}
return RedirectToAction(ControllerActions.Edit, new { id });
}
这是一种简单的方法。它需要用户ID和密码更改表单的视图模型。如果模型状态有效,它将从服务层检索用户并调用函数以检查其旧密码。管理员不必提供用户的旧密码,他们自己就足够了。如果密码正确,则调用更改用户密码的功能。如果成功或失败,将在TempData中放置适当的消息。操作以重定向到用户编辑页面结束,其中包含用于更改密码的表单并显示所有错误。
我几乎没有问题:
代码中使用的接口和类(实现是在构造函数中注入的,但没关系):
public interface IModelStateWrapper
{
void AddModelError(string name, string error);
bool IsValid { get; }
}
public interface IUserService
{
User GetUserByID(int id);
bool ChangePassword(string userName, string newPassword);
}
public interface ILoginService
{
bool CheckPassword(string userName, string password);
}
public interface ITempDataWrapper
{
string Message { get; set; }
}
public class UserChangePasswordVM : IValidatableObject
{
[DataType(DataType.Password)]
public string OldPassword { get; set; }
[DataType(DataType.Password)]
public string NewPassword { get; set; }
[DataType(DataType.Password)]
public string NewPasswordConfirmation { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (string.IsNullOrEmpty(NewPassword))
yield return new ValidationResult(CTRes.PasswordNotEmpty, new[] { "NewPassword" });
if (string.IsNullOrEmpty(NewPasswordConfirmation))
yield return new ValidationResult(CTRes.ConfirmPassword, new[] { "NewPasswordConfirmation" });
if (NewPassword != null)
if (!NewPassword.Equals(NewPasswordConfirmation))
yield return new ValidationResult(CTRes.PasswordsDontMatch, new[] { "NewPasswordConfirmation" });
}
}
答案 0 :(得分:2)
单元测试应该简单易懂。您应该避免在单个测试中测试大量场景。因为如果某些断言失败,那么您不知道以下断言会发生什么。单元测试是一种文档。你应该把较大的那些分成小的,这样你就可以很好地控制单元测试。
我最近开始进行单元测试,尤其是ASP.NET MVC项目。每当我看到...我会去做两次测试。如果我有这样的控制器动作,那么以下是我将要编写的单元测试。
<强> 1。行动结果测试
这是一个简单的测试,在此测试中,我将检查输出操作结果是否包含操作名称ControllerActions.Edit
和路由值中的id
。由于无论条件如何,总是以相同的值返回相同的动作结果,因此单元测试就足够了。
<强> 2。角色测试
所以在这里,我将为admin
编写两个单元测试,其余为其余部分。我将为_loginService
创建一个模拟,并设置期望,以便当用户为admin
时,_loginService
将使用我在CurrentPrincipal.User.UserName
中设置的值进行调用。 (那CurrentPrincipal
是一个自定义对象吗?我不确定你是怎么去嘲笑它的。)
在非管理员测试中,我将在模拟对象中设置期望值,以便user.UserName
以{I}值传递给_loginService
。
在后面的测试中,我要模拟_userService
并存根GetUserByID
方法以返回自定义用户。
第3。测试正确/错误的旧密码
在这里,我将编写两个测试用例。如果旧密码是正确的,我是否在TempData
中获得了一些值,那么应该没有模型错误,而另一个测试则反之亦然。
<强> 4。密码更改成功/失败测试
这里我们可能需要两个测试用例,以便在密码成功更改或由于某些例外而失败时在TempData
中测试返回的messaged。