खोज…


दृश्य मॉडलों का परीक्षण

हमारे शुरू करने से पहले...

एप्लिकेशन लेयर्स के संदर्भ में आपका ViewModel एक ऐसा वर्ग है जिसमें सभी व्यावसायिक तर्क और नियम हैं, जो ऐप को आवश्यकताओं के अनुसार बनाते हैं। यूआई, डेटा लेयर, देशी फीचर्स और एपीआई कॉल आदि के संदर्भों को जितना संभव हो उतना कम स्वतंत्र बनाना भी महत्वपूर्ण है, ये सभी आपके वीएम को परीक्षण योग्य बनाते हैं।
संक्षेप में, आपका ViewModel:

  • यूआई कक्षाओं (विचारों, पृष्ठों, शैलियों, घटनाओं) पर निर्भर नहीं होना चाहिए;
  • अन्य वर्गों के स्थिर डेटा (जितना आप कर सकते हैं) का उपयोग नहीं करना चाहिए;
  • व्यवसाय तर्क को लागू करना चाहिए और यूआई पर होने के लिए डेटा तैयार करना चाहिए;
  • निर्भरता इंजेक्शन का उपयोग करके हल किए जा रहे इंटरफेस के माध्यम से अन्य घटकों (डेटाबेस, HTTP, यूआई-विशिष्ट) का उपयोग करना चाहिए।

आपके ViewModel में दूसरे VMs प्रकार के गुण भी हो सकते हैं। उदाहरण के लिए ContactsPageViewModel पास ObservableCollection<ContactListItemViewModel> प्रकार जैसे संग्रह प्रकार की ObservableCollection<ContactListItemViewModel>

व्यापार की आवश्यकताओं

मान लें कि लागू करने के लिए हमारे पास निम्न कार्यक्षमता है:

As an unauthorized user
I want to log into the app
So that I will access the authorized features

उपयोगकर्ता कहानी को स्पष्ट करने के बाद हमने निम्नलिखित परिदृश्यों को परिभाषित किया:

Scenario: trying to log in with valid non-empty creds
  Given the user is on Login screen
   When the user enters 'user' as username
    And the user enters 'pass' as password
    And the user taps the Login button
   Then the app shows the loading indicator
    And the app makes an API call for authentication

Scenario: trying to log in empty username
  Given the user is on Login screen
   When the user enters '  ' as username
    And the user enters 'pass' as password
    And the user taps the Login button
   Then the app shows an error message saying 'Please, enter correct username and password'
    And the app doesn't make an API call for authentication

हम केवल इन दो परिदृश्यों के साथ रहेंगे। बेशक, बहुत अधिक मामले होने चाहिए और आपको वास्तविक कोडिंग से पहले उन सभी को परिभाषित करना चाहिए, लेकिन यह हमारे लिए पर्याप्त है कि अब हम दृश्य मॉडलों के यूनिट परीक्षण से परिचित हों।

आइए शास्त्रीय टीडीडी दृष्टिकोण का पालन करें और एक खाली वर्ग को लिखने के साथ शुरू किया जा रहा है। फिर हम परीक्षण लिखेंगे और व्यवसाय की कार्यक्षमता को लागू करके उन्हें हरा बना देंगे।

सामान्य वर्ग

public abstract class BaseViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

सेवाएं

क्या आपको याद है कि हमारे व्यू मॉडल को सीधे यूआई और एचटीटीपी कक्षाओं का उपयोग नहीं करना चाहिए? आपको उन्हें अमूर्त के रूप में परिभाषित करना चाहिए और कार्यान्वयन विवरण पर निर्भर नहीं होना चाहिए।

/// <summary>
/// Provides authentication functionality.
/// </summary>
public interface IAuthenticationService
{
    /// <summary>
    /// Tries to authenticate the user with the given credentials.
    /// </summary>
    /// <param name="userName">UserName</param>
    /// <param name="password">User's password</param>
    /// <returns>true if the user has been successfully authenticated</returns>
    Task<bool> Login(string userName, string password);
}

/// <summary>
/// UI-specific service providing abilities to show alert messages.
/// </summary>
public interface IAlertService
{
    /// <summary>
    /// Show an alert message to the user.
    /// </summary>
    /// <param name="title">Alert message title</param>
    /// <param name="message">Alert message text</param>
    Task ShowAlert(string title, string message);
}

व्यूमॉडल स्टब का निर्माण

ठीक है, हमारे पास लॉगिन स्क्रीन के लिए पेज क्लास है, लेकिन पहले ViewModel से शुरू करते हैं:

public class LoginPageViewModel : BaseViewModel
{
    private readonly IAuthenticationService authenticationService;
    private readonly IAlertService alertService;

    private string userName;
    private string password;
    private bool isLoading;

    private ICommand loginCommand;

    public LoginPageViewModel(IAuthenticationService authenticationService, IAlertService alertService)
    {
        this.authenticationService = authenticationService;
        this.alertService = alertService;
    }

    public string UserName
    {
        get
        {
            return userName;
        }
        set
        {
            if (userName!= value)
            {
                userName= value;
                OnPropertyChanged();
            }
        }
    }
    
    public string Password
    {
        get
        {
            return password;
        }
        set
        {
            if (password != value)
            {
                password = value;
                OnPropertyChanged();
            }
        }
    }

    public bool IsLoading
    {
        get
        {
            return isLoading;
        }
        set
        {
            if (isLoading != value)
            {
                isLoading = value;
                OnPropertyChanged();
            }
        }
    }

    public ICommand LoginCommand => loginCommand ?? (loginCommand = new Command(Login));

    private void Login()
    {
        authenticationService.Login(UserName, Password);
    }
}

हमने UI पर बाध्य होने के लिए दो string गुण और एक कमांड परिभाषित किया है। हम इस विषय में पृष्ठ वर्ग, XAML मार्कअप और बाइंड व्यूमॉडल को इस विषय में बनाने का वर्णन नहीं करेंगे क्योंकि उनके पास कुछ विशिष्ट नहीं है।

LoginPageViewModel उदाहरण कैसे बनाएं?

मुझे लगता है कि आप शायद सिर्फ कंस्ट्रक्टर के साथ वीएम बना रहे थे। अब जैसा कि आप देख सकते हैं कि हमारा वीएम 2 सेवाओं पर निर्भर करता है जो कि कंस्ट्रक्टर पैरामीटर के रूप में इंजेक्ट किया जा सकता है इसलिए केवल var viewModel = new LoginPageViewModel() । यदि आप निर्भरता इंजेक्शन से परिचित नहीं हैं, तो इसके बारे में जानने के लिए यह सबसे अच्छा क्षण है। इस सिद्धांत को जाने और अनुसरण किए बिना उचित इकाई-परीक्षण असंभव है।

टेस्ट

अब ऊपर सूचीबद्ध मामलों के उपयोग के अनुसार कुछ परीक्षण लिखें। सबसे पहले आपको एक नई असेंबली बनाने की आवश्यकता है (यदि आप Microsoft इकाई परीक्षण उपकरणों का उपयोग करना चाहते हैं तो केवल एक क्लास लाइब्रेरी या एक विशेष परीक्षण परियोजना का चयन करें)। इसे ProjectName.Tests जैसा कुछ नाम दें और अपने मूल PCL प्रोजेक्ट का संदर्भ जोड़ें।

मैं इस उदाहरण मैं NUnit और Moq का उपयोग करने जा रहा हूँ, लेकिन आप अपने choise के किसी भी परीक्षण के साथ जा सकते हैं। उनके साथ कुछ खास नहीं होगा।

ठीक है, वह टेस्ट क्लास है:

[TestFixture]
public class LoginPageViewModelTest
{
}

लेखन परीक्षण

यहां पहले दो परिदृश्यों के लिए परीक्षण विधियां दी गई हैं। 1 अपेक्षित परिणाम के अनुसार 1 परीक्षा विधि रखने की कोशिश करें और एक परीक्षा में सब कुछ जांचने के लिए नहीं। यह आपको कोड में विफल होने के बारे में स्पष्ट रिपोर्ट प्राप्त करने में मदद करेगा।

[TestFixture]
public class LoginPageViewModelTest
{
    private readonly Mock<IAuthenticationService> authenticationServiceMock =
        new Mock<IAuthenticationService>();
    private readonly Mock<IAlertService> alertServiceMock =
        new Mock<IAlertService>();
    
    [TestCase("user", "pass")]
    public void LogInWithValidCreds_LoadingIndicatorShown(string userName, string password)
    {
        LoginPageViewModel model = CreateViewModelAndLogin(userName, password);

        Assert.IsTrue(model.IsLoading);
    }

    [TestCase("user", "pass")]
    public void LogInWithValidCreds_AuthenticationRequested(string userName, string password)
    {
        CreateViewModelAndLogin(userName, password);

        authenticationServiceMock.Verify(x => x.Login(userName, password), Times.Once);
    }

    [TestCase("", "pass")]
    [TestCase("   ", "pass")]
    [TestCase(null, "pass")]
    public void LogInWithEmptyuserName_AuthenticationNotRequested(string userName, string password)
    {
        CreateViewModelAndLogin(userName, password);

        authenticationServiceMock.Verify(x => x.Login(It.IsAny<string>(), It.IsAny<string>()), Times.Never);
    }

    [TestCase("", "pass", "Please, enter correct username and password")]
    [TestCase("   ", "pass", "Please, enter correct username and password")]
    [TestCase(null, "pass", "Please, enter correct username and password")]
    public void LogInWithEmptyUserName_AlertMessageShown(string userName, string password, string message)
    {
        CreateViewModelAndLogin(userName, password);

        alertServiceMock.Verify(x => x.ShowAlert(It.IsAny<string>(), message));
    }

    private LoginPageViewModel CreateViewModelAndLogin(string userName, string password)
    {
        var model = new LoginPageViewModel(
            authenticationServiceMock.Object,
            alertServiceMock.Object);

        model.UserName = userName;
        model.Password = password;

        model.LoginCommand.Execute(null);

        return model;
    }
}

और अब हम चले:

यहाँ छवि विवरण दर्ज करें

अब लक्ष्य ViewModel की Login विधि के लिए सही कार्यान्वयन लिखना है और यही वह है।

व्यापार तर्क कार्यान्वयन

private async void Login()
{
    if (String.IsNullOrWhiteSpace(UserName) || String.IsNullOrWhiteSpace(Password))
    {
        await alertService.ShowAlert("Warning", "Please, enter correct username and password");
    }
    else
    {
        IsLoading = true;
        bool isAuthenticated = await authenticationService.Login(UserName, Password);
    }
}

और फिर से परीक्षण चलाने के बाद:

यहाँ छवि विवरण दर्ज करें

अब आप अपने कोड को नए परीक्षणों के साथ और अधिक स्थिर और प्रतिगमन-सुरक्षित बना सकते हैं।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow