簡體   English   中英

WPF MVVM Light單元測試ViewModels

[英]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 ) - 當屬性值更改時會引發該事件。 由於這是很多樣板代碼,因此強烈建議使用工具/ 自動執行此過程。
  • 您確實希望有兩組測試 ,一組用於視圖模型(如上例所示),另一組用於基礎業務邏輯(原始測試)。 在MVVM中,VM是額外的層,可能看起來沒用 - 但這就是重點 - 在那里沒有業務邏輯,而是集中數據重新排列/准備視圖層。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM