WCSF – Using Session State in Unit Tests
Posted by Vlad on September 28, 2007
The Web Client Software Factory provides a handy class, StateValue<T>, to use for storing values in Session. From the WCSF help:
This class supports code that runs both in a Web server environment (the session is available, and data is stored there) and outside of a Web server environment (no session is available, such as when you run your unit tests, and the data is stored in memory).
To use it, just declare a public field of StateValue<T> type and the Object Builder injects the object:
public StateValue<MyType> MyStoredValue;
To access it, just use the Value property:
MyStoredValue.Value = new MyType();
This works fine when running the application in the web server. When unit testing however, you’ll notice that the field remains null, because the object builder used for the MockCompositionContainer lacks the strategy that deals with the StateValue<T> fields. Unfortunately, the Reference Implementation that comes with WCSF doesn’t make use of these type of fields so there is no quick example on how to deal with them in tests. You can use the tests covering the builder strategies from the CompositeWeb application block tests, or you can use the following quick reference and save yourself the digging
.
The StateValue<T> fields are injected by the SessionStateBindingStrategy. This in turn uses the ISessionStateLocatorService service to obtain an IHttpSessionState object that will act as a repository.
So the first step is to implement a MockHttpSessionState class:
public class MockHttpSessionState : IHttpSessionState
{
public Hashtable Values = new Hashtable();
public object this[string name]
{
get
{
return Values[name];
}
set
{
Values[name] = value;
}
}
// other IHttpSessionState members
}
We can now write a MockSessionStateLocatorService:
public class MockSessionStateLocatorService : ISessionStateLocatorService
{
public MockHttpSessionState SessionState = new MockHttpSessionState();
public System.Web.SessionState.IHttpSessionState GetSessionState()
{
return SessionState;
}
}
The MockCompositionContainer initializes the builder with our mock service and adds the SessionStateBindingStrategy strategy:
class MockCompositionContainer : CompositionContainer
{
public WCSFBuilder CreatedBuilder;
public MockCompositionContainer()
{
InitializeRootContainer(CreateBuilder());
this.Services.AddNew<MockSessionStateLocatorService, ISessionStateLocatorService>();
CreatedBuilder.Strategies.AddNew<SessionStateBindingStrategy>(BuilderStage.Initialization);
}
private WCSFBuilder CreateBuilder()
{
WCSFBuilder builder = new WCSFBuilder();
CreatedBuilder = builder;
builder.Policies.SetDefault<ISingletonPolicy>(new SingletonPolicy(true));
return builder;
}
}
Now the StateValue<T> field gets injected:
[Test]
public void ProvidesAnnouncementToAdd()
{
MockCompositionContainer rootContainer = new MockCompositionContainer();
CompositionContainer moduleContainer = rootContainer.Containers.AddNew<CompositionContainer>();
MyPresenter presenter = moduleContainer.BuildNewItem(typeof(MyPresenter)) as MyPresenter;
Assert.IsNotNull(presenter.MyStateField);
}
Mavrick said
Hi,
I tried most possible ways from my side to get the ModuleContainerLocatorService in Test Module(* i e in my Test Method),
CompositionContainer ccTest = new CompositionContainer();
ccTest.InitializeRootContainer(new WCSFBuilder());
ccTest.InitializeContainer();
ModuleContainerLocatorService mlcsCurrent = new ModuleContainerLocatorService(null);
ccTest.Services.Add(mlcsCurrent);
object oTest = ccTest.BuildNewItem(typeof(DefaultViewPresenter));
But still i am getting servicemissingException when it returns from controller of main module.
Please reply where I am doing mistake..
Vlad said
You have to let the container create the service:
ModuleContainerLocatorService mlcsCurrent = ccTest.Services.AddNew < ModuleContainerLocatorService > ();Let me know if this helps.
D said
I’m having trouble getting this to work in the case where my presenter has a constructor that requires a controller (with injection dependency).
For example, when my presenter has the following constructor, I get an “Invalid Type Owner for Dynamic Method” error:
public MyPresenter([CreateNew] IMyController controller)
{
_controller = controller;
}
If I have a default constructor, the everything works fine…but my presenter doesn’t have a controller.
Is there a way to configure my MockCompositeContainer so that I can use the dependency injection constructor on the presenter?