Reputation: 9568
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
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