tsJensen

A quest for software excellence...

DomainAspects: Inject Fake PrincipalProvider and Avoid Fake HttpContext for Testing

Today I began playing with the DomainAspects project again and realized that my tests were breaking when I switched to the .NET 4.0 Framework. After a little research, it became clear. My test helper class in the previous version of DomainAspects committed a Class A coding misdemeanor. It relied on reflection to set the value of a private member on object returned by an internal method in the Thread class.

In my own defense, I did not write that code. I borrrowed it from somewhere online to allow me to set the HttpContext even when there really isn't one available when I run my tests. This was clearly bad form and came back to bite me. So I decided to eliminate the need and just added a facility in my DomainFactory class to substitute one or more of the Windsor components used by the DomainFactory.Create<T> method which is wrapped in an IDisposable via the DomainProxy<T> class being used in the tests.

Here is the simple addition to the DomainFactory. Note that we must remove these components in reverse order and then add them back since there are dependencies involved. Also note that this method will fail if you have already created an instance of a domain interface using the proxy or factory class.

/// <summary>
/// Replaces default aspect oriented operations components with client supplied components.
/// Used for testing or customizing operations withing the factory IoC container.
/// </summary>
/// <param name="principalProviderType"></param>
/// <param name="operationAuthorizerType"></param>
/// <param name="operationAuditorType"></param>
/// <param name="operationInterceptorType"></param>
/// <exception cref=""></exception>
public static void SubstituteComponents(
	Type principalProviderType = null, 
	Type operationAuthorizerType = null, 
	Type operationAuditorType = null)
{
	//set default types where param is null otherwise check for proper interface
	if (principalProviderType == null)
		principalProviderType = typeof(PrincipalProvider);
	else if (principalProviderType.GetInterface(typeof(IPrincipalProvider).FullName) == null)
		throw new ApplicationException("principalProviderType is not of type IPrincipalProvider.");
		
	if (operationAuthorizerType == null) 
		operationAuthorizerType = typeof(OperationAuthorizer);
	else if (operationAuthorizerType.GetInterface(typeof(IOperationAuthorizer).FullName) == null)
		throw new ApplicationException("operationAuthorizerType is not of type IOperationAuthorizer.");

	if (operationAuditorType == null) 
		operationAuditorType = typeof(OperationAuditor);
	else if (operationAuditorType.GetInterface(typeof(IOperationAuditor).FullName) == null)
		throw new ApplicationException("operationAuditorType is not of type IOperationAuditor.");


	if (container.Kernel.RemoveComponent("OperationInterceptor")
		&& container.Kernel.RemoveComponent("OperationAuditor")
		&& container.Kernel.RemoveComponent("OperationAuthorizer")
		&& container.Kernel.RemoveComponent("PrincipalProvider"))
	{
		container.Register(
			Component.For<IPrincipalProvider>()
				.ImplementedBy(principalProviderType)
				.Named("PrincipalProvider")
				.LifeStyle.Transient,

			Component.For<IOperationAuthorizer>()
			.ImplementedBy(operationAuthorizerType)
			.Named("OperationAuthorizer")
			.LifeStyle.Transient,

			Component.For<IOperationAuditor>()
			.ImplementedBy(operationAuditorType)
			.Named("OperationAuditor")
			.LifeStyle.Transient,

			Component.For<OperationInterceptor>()
			.Named("OperationInterceptor")
			.LifeStyle.Transient);
	}
	else
	{
		throw new ApplicationException("SubstituteComponents failed due to invoked component dependencies.");
	}
}

Once the new method was added to the DomainFactory class, I removed the TestHelper.cs file which included this very naughty code which fails in .NET 4.0 because the implementation of the Thread class changed and the GetIllogicalCallContext internal method went away.

//broken in .NET 4.0 - GetIllogicalCallContext does not exist in Thread class anymore
public static void SetCurrentContext(string fileName, string url, string queryString, FakePrincipal principal)
{
	var context = CreateHttpContext(fileName, url, queryString);
	context.User = principal;
	var result = RunInstanceMethod(Thread.CurrentThread, "GetIllogicalCallContext", new object[] { });
	SetPrivateInstanceFieldValue(result, "m_HostContext", context);
}

Now that the offending code is gone, the RegistrationServiceTests test class is broken as you see below:

[TestInitialize]
public void Initialize()
{
	//set up a fake http context with fake IPrincipal
	string[] roles =
		{
			 "Admin",
			 "User",
			 "Local Office"
		};
	TestHelper.SetCurrentContext(new FakePrincipal("Fake", "testuser", true, roles));
}

I replaced that code with this:

static bool isInitialized = false;

[TestInitialize]
public void Initialize()
{
	if (!isInitialized)
	{
		isInitialized = true;
		//only do this once per test/process run
		DomainFactory.SubstituteComponents(typeof(FakePrincipleProvider));
	}
}

And created the new FakePrincipleProvider class to create and deliver the IPrincipal as required by the IPrincipalProvider:

public class FakePrincipleProvider : IPrincipalProvider
{
	FakePrincipal principal;

	public IPrincipal GetPrincipal()
	{
		if (principal == null)
		{
			string[] roles =
			{
				 "Admin",
				 "User",
				 "Local Office"
			};
			principal = new FakePrincipal("Fake", "testuser", true, roles);
		}
		return principal;
	}
}

And now my tests pass again because my IoC container is passing along the FakePrincipleProvider to my OperationAuthorizer class.

There will be more to come with DomainAspects soon.

DomainAspects_v1_2.zip (2.97 MB)