[英]WPF MVVM Light unit testing ViewModels
我不是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>();
}
}
}
登錄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");
}
});
}
}
綁定和命令工作正常,所以沒有問題。 設計和測試時間的業務模型類:
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
};
}
}
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));
}
}
現在我的測試不在ViewModel本身上,而是直接在Business層上。
基本上我有兩個問題:
我是在正確的道路上,還是我的模式實施存在根本缺陷?
我該如何測試我的ViewModel?
您的視圖模型有一個值得測試的相關代碼,即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();
這樣,您可以驗證該命令是否按預期調用業務層。 請注意,匹配參數時會忽略Action<bool>
- 很難匹配Action<T>
和Func<T>
並且通常不值得。
幾點說明:
Action
參數) INotifyPropertyChanged
屬性(在您的情況下為UserName
) - 當屬性值更改時會引發該事件。 由於這是很多樣板代碼,因此強烈建議使用工具/ 庫自動執行此過程。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.