Patrick Peters
Patrick Peters

Reputation: 9568

How to configure Moq to make use of generic action<T>

I have a facade class that uses a WCF client proxy. To prevent issues with the WCF proxy client with IDispose (bug in WCF, still not fixed by MS), I have created a generic proxy service to do the basic plumbing for calling the WCF service.

I want to unit test the facade with Moq, and I have an issue how to get into specific call within a unit test using Moq. The unit test wants to verify that the call to the process manager was done just once, but the code does not flow within the 'Use' method....


(edit) For completeness here is the part that fixed the issue:

public AuthenticationFacade CreateSut()
        {
            ProcessManager = new Mock<IProcessManager>().Object;
            SessionWrapper = new Mock<ISessionWrapper>().Object;

            AuthenticationClientProxy = new Mock<Action<IAuthentication>>().Object;

            var authenticationProxyServiceMock = new Mock<IProxyService<IAuthentication>>();

            Mock<IAuthentication> mockAuthentication = new Mock<IAuthentication>();
            authenticationProxyServiceMock.Setup(aps => aps.Use(It.IsAny<Action<IAuthentication>>()))
                          .Callback<Action<IAuthentication>>(ac => ac(mockAuthentication.Object));

            AuthenticationProxyService = authenticationProxyServiceMock.Object;

            return new AuthenticationFacade(ProcessManager, SessionWrapper, AuthenticationProxyService);
        }

(reference code)

Code part 1:

    using System;

    namespace Progis.Kim
    {
        public interface IProxyService<T>
        {
            void Use(Action<T> action);
        }
    }

Code part 2:

/// <summary>
    /// Helper class to fix the WCF Client Proxy usage bug with IDispose.
    /// Check: http://benmccallum.wordpress.com/2011/08/27/wcf-web-service-wrapper-closing-disposing-and-aborting-best-practices/
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ProxyService<T> : IProxyService<T>
    {
        public void Use(Action<T> action)
        {
            <cut>....
        }
    }

Code part 3:

public class AuthenticationFacade : IAuthenticationFacade
    {
        private readonly IProcessManager processManager;
        private readonly ISessionWrapper sessionWrapper;
        private readonly IProxyService<IAuthentication> authenticationProxyService;

        public AuthenticationFacade(
            IProcessManager processManager, 
            ISessionWrapper sessionWrapper, 
            IProxyService<IAuthentication> authenticationProxyService)
        {
            this.processManager = processManager;
            this.sessionWrapper = sessionWrapper;
            this.authenticationProxyService = authenticationProxyService;
        }

        public bool ValidateGebruiker(string gebruikernaam, string wachtwoord)
        {
            bool authenticated = false;


            authenticationProxyService.Use(client =>
            {
                var sessionId = processManager.GetSessionId();

                  authenticated = client.ValidateGebruiker(
                    sessionId,
                    gebruikernaam,
                    wachtwoord);
            });

            return authenticated;
        }

Code part 4:

public class AuthenticationFacadeFixture
    {
        public IProcessManager ProcessManager { get; set; }

        public ISessionWrapper SessionWrapper { get; set; }

        public IProxyService<IAuthentication> AuthenticationProxyService { get; set; }

        public AuthenticationFacade CreateSut()
        {
            ProcessManager = new Mock<IProcessManager>().Object;
            SessionWrapper = new Mock<ISessionWrapper>().Object;
            AuthenticationProxyService = new Mock<IProxyService<IAuthentication>>().Object;

            return new AuthenticationFacade(ProcessManager, SessionWrapper, AuthenticationProxyService);
        }
    }

Code part 5:

public static class MockExtensions
    {
        public static Mock<T> AsMock<T>(this T obj) where T : class
        {
            return Mock.Get(obj);
        }
    }

Code part 6 (unit test):

[TestMethod]
        public void ValidateGebruiker_calls_processmanager_getsessionid_once()
        {
            // Arrange
            var fixture = new AuthenticationFacadeFixture();
            var sut = fixture.CreateSut();

            var validUserPass = CreateValidGebruikersnaamWachtwoord();

            // Act
            sut.ValidateGebruiker(validUserPass.Gebruikersnaam, validUserPass.Wachtwoord);

            // Assert
            fixture.ProcessManager.AsMock().Verify(pm => pm.GetSessionId(), Times.Once());
        }

Upvotes: 2

Views: 481

Answers (1)

Patrick Quirk
Patrick Quirk

Reputation: 23747

You've omitted your Moq setup code which makes this a little harder, but I believe it looks something like this:

AuthenticationProxyService.Setup(a => a.Use(It.IsAny<Action<IAuthentication>>()));

If so, you can do the following:

// Not sure if you have this mock already, this is the "client" variable
// in your Use method action
Mock<IAuthentication> mockAuthentication = mockRepository.Create<IAuthentication>();

AuthenticationProxyService.Setup(a => a.Use(It.IsAny<Action<IAuthentication>>()))
                          .Callback<Action<IAuthentication>>(a => a(mockAuthentication.Object));

The Callback method receives the parameter from the Setup (an Action<IAuthentication>) which in this case is the code in ValidateGebruiker, and just invokes it with a mocked IAuthentication object (which you'll need to Setup if you don't already).

Upvotes: 1

Related Questions