Search code examples
c#unit-testingtestingnunitrelaycommand

How do I write a Unit test for a RelayCommand that contains an Async Service Call?


I have a RelayCommand that I am trying to test. The RelayCommand contains a Service Call to Authenticate my user. Shown below:

private MvxCommand _signIn;
public MvxCommand SignIn
{
    get
    {
        return _signIn ?? (_signIn = new MvxCommand(() =>
        {
            BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
            EndpointAddress endpoint = new EndpointAddress(AppResources.AuthService);
            var client = new MyService(binding, endpoint);
            client.AuthorizeCompleted += ((sender, args) =>
            {
                try
                {
                    if (args.Result)
                    {
                        //Success.. Carry on
                    }
                }
                catch (Exception ex)
                {
                    //AccessDenied Exception thrown by service
                    if (ex.InnerException != null && string.Equals(ex.InnerException.Message, "Access is denied.", StringComparison.CurrentCultureIgnoreCase))
                    {
                        //Display Message.. Incorrect Credentials
                    }
                    else
                    {
                        //Other error... Service down?
                    }
                }
            });

            client.AuthorizeAsync(UserName, Password, null);

        }));
    }
}

But now I am using NUnit to test my ViewModels and I am stumped on how to test my RelayCommand

I can do:

[Test]
public void PerformTest()
{
    ViewModel.SignIn.Execute();
}

But this returns no information on whether the SignIn method succeeded or not.

How do I test a RelayCommand containing a Service Call?


Solution

  • So in the end I used Dependency Injection to inject a service into the constructor of my viewmodel like so:

    public IMyService client { get; set; }
    
    public MyClass(IMyService myservice)
    {
        client = myservice
    }
    

    I can then refactor my SignIn method like so:

    private MvxCommand _signIn;
    public MvxCommand SignIn
    {
        get
        {
            return _signIn ?? (_signIn = new MvxCommand(() =>
            {
                client.AuthorizeCompleted += ((sender, args) =>
                {
                    try
                    {
                        if (args.Result)
                        {
                            //Success.. Carry on
                        }
                    }
                    catch (Exception ex)
                    {
                        //AccessDenied Exception thrown by service
                        if (ex.InnerException != null && string.Equals(ex.InnerException.Message, "Access is denied.", StringComparison.CurrentCultureIgnoreCase))
                        {
                            //Display Message.. Incorrect Credentials
                        }
                        else
                        {
                            //Other error... Service down?
                        }
                    }
                });
                client.AuthorizeAsync(UserName, Password, null); 
            }));
        }
    }
    

    and test my ViewModel using a mock service using the Assign-Act-Assert design pattern:

        [Test]
        public void PerformTest()
        {
            List<object> objs = new List<object>();
            Exception ex = new Exception("Access is denied.");
            objs.Add(true);
    
            AuthorizeCompletedEventArgs incorrectPasswordArgs = new AuthorizeCompletedEventArgs(null, ex, false, null);
            AuthorizeCompletedEventArgs correctPasswordArgs = new AuthorizeCompletedEventArgs(objs.ToArray(), null, false, null);
    
            Moq.Mock<IMyService> client = new Mock<IMyService>();
    
            client .Setup(t => t.AuthorizeAsync(It.Is<string>((s) => s == "correct"), It.Is<string>((s) => s == "correct"))).Callback(() =>
            {
                client.Raise(t => t.AuthorizeCompleted += null, correctPasswordArgs);
            });
    
    
            client.Setup(t => t.AuthorizeAsync(It.IsAny<string>(), It.IsAny<string>())).Callback(() =>
            {
                client.Raise(t => t.AuthorizeCompleted += null, incorrectPasswordArgs);
            });
    
            var ViewModel = new MyClass(client.Object);
    
            ViewModel.UserName = "correct";
            ViewModel.Password = "correct";
            ViewModel.SignIn.Execute();
        }