Rog*_*Far 11 c# wpf unit-testing mvvm mvvm-light
我不是MVVM模式的常规,这基本上是我第一次玩它.
我以前做的("普通"WPF)是用业务层创建我的视图,也许是数据层(通常包含我的服务或实体框架创建的实体).
现在经过一些玩弄我从MVVM Light创建了一个标准模板,并做到了这一点:
定位:
public class ViewModelLocator
{
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (ViewModelBase.IsInDesignModeStatic)
{
SimpleIoc.Default.Register<IUserService, DesignUserService>();
}
else
{
SimpleIoc.Default.Register<IUserService, IUserService>();
}
SimpleIoc.Default.Register<LoginViewModel>();
}
public LoginViewModel Login
{
get
{
return ServiceLocator.Current.GetInstance<LoginViewModel>();
}
}
}
Run Code Online (Sandbox Code Playgroud)
登录ViewModel:
public class LoginViewModel : ViewModelBase
{
private readonly IUserService _userService;
public RelayCommand<Object> LoginCommand
{
get
{
return new RelayCommand<Object>(Login);
}
}
private string _userName;
public String UserName
{
get { return _userName; }
set
{
if (value == _userName)
return;
_userName = value;
RaisePropertyChanged("UserName");
}
}
/// <summary>
/// Initializes a new instance of the LoginViewModel class.
/// </summary>
public LoginViewModel(IUserService userService)
{
_userService = userService;
_closing = true;
}
private void Login(Object passwordBoxObject)
{
PasswordBox passwordBox = passwordBoxObject as PasswordBox;
if (passwordBox == null)
throw new Exception("PasswordBox is null");
_userService.Login(UserName, passwordBox.SecurePassword, result =>
{
if (!result)
{
MessageBox.Show("Wrong username or password");
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
绑定和命令工作正常,所以没有问题.设计和测试时间的业务模型类:
public class DesignUserService : IUserService
{
private readonly User _testUser;
private readonly IList<User> _users;
public void Login(String userName, SecureString password, Action<Boolean> callback)
{
var user = _users.FirstOrDefault(u => u.UserName.ToLower() == userName.ToLower());
if (user == null)
{
callback(false);
return;
}
String rawPassword = Security.ComputeHashString(password, user.Salt);
if (rawPassword != user.Password)
{
callback(false);
return;
}
callback(true);
}
public DesignUserService()
{
_testUser = new User
{
UserName = "testuser",
Password = "123123",
Salt = "123123"
};
_users = new List<User>
{
_testUser
};
}
}
Run Code Online (Sandbox Code Playgroud)
UserData是一个静态类,它调用数据库(Entity Framework).
现在我有我的测试:
[TestClass]
public class Login
{
[TestMethod]
public void IncorrectUsernameCorrectPassword()
{
IUserService userService = new DesignUserService();
PasswordBox passwordBox = new PasswordBox
{
Password = "password"
};
userService.Login("nonexistingusername", passwordBox.SecurePassword, b => Assert.AreEqual(b, false));
}
}
Run Code Online (Sandbox Code Playgroud)
现在我的测试不在ViewModel本身上,而是直接在Business层上.
基本上我有两个问题:
我是在正确的道路上,还是我的模式实施存在根本缺陷?
我该如何测试我的ViewModel?
k.m*_*k.m 15
您的视图模型有一个相关的代码片段值得测试,这是Login方法.鉴于它是私有的,应该通过它进行测试LoginCommand.
现在,有人可能会问,当您已经测试了基础业务逻辑时,测试命令的目的是什么?目的是验证调用业务逻辑并使用正确的参数.
如何进行这样的测试?通过使用模拟.FakeItEasy示例:
var userServiceFake = A.Fake<IUserService>();
var testedViewModel = new LoginViewModel(userServiceFake);
// prepare data for test
var passwordBox = new PasswordBox { Password = "password" };
testedViewModel.UserName = "TestUser";
// execute test
testedViewModel.LoginCommand.Execute(passwordBox);
// verify
A.CallTo(() => userServiceFake.Login(
"TestUser",
passwordBox.SecurePassword,
A<Action<bool>>.Ignored)
).MustHaveHappened();
Run Code Online (Sandbox Code Playgroud)
这样,您可以验证该命令是否按预期调用业务层.请注意,Action<bool>匹配参数时会忽略它 - 它很难匹配Action<T>,Func<T>而且通常不值得.
几点说明:
Action参数)INotifyPropertyChanged属性(UserName在您的情况下) - 当属性值更改时会引发该事件.由于这是很多样板代码,因此强烈建议使用工具/ 库自动执行此过程.| 归档时间: |
|
| 查看次数: |
8822 次 |
| 最近记录: |