2

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?

JKennedy
  • 18,150
  • 17
  • 114
  • 198
  • This looks like an integration test to me as opposed to a unit test. Which unit are you interested in testing? If it is the view model, you could/should inject a dummy(test) function to test that the correct args are being sent. – F5 F5 F5 Sep 21 '15 at 12:20
  • I'm new to automated testing, but looking at it you might be right this possibly is an integration test. I'm testing my viewmodel. If I use a dummy view model. This won't test my service, is there another method for service testing? – JKennedy Sep 21 '15 at 13:02
  • To test your viewmodel, don't use a dummy viewmode. Inject a test method into your viewmodel that you can uses to make sure that your viewmodel is calling your service correctly. You should call a proxy from inside The source of the service service itself should have its own unit tests. If you want to do end-to-end integration testing, it will be difficult to automate. Sorry, if I had an answer to the problem I would have put in an answer. All I can do is try to shed more light on the problem. – F5 F5 F5 Sep 21 '15 at 13:35
  • @F5F5F5 Thanks for a point in the right direction. I think I understand what you are saying and will hopefully post an answer here soon – JKennedy Sep 21 '15 at 13:46

1 Answers1

1

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();
    }
JKennedy
  • 18,150
  • 17
  • 114
  • 198