One of our customers had a very interesting problem. When using he needed to set WCF’s WebOperationContext.Current.IncomingRequest.UserAgent to return a specific string.
Usually this would not have been a problem using the AAA API:
1 |
<span id="lnum1" style="color: #606060"> 1:</span> Isolate.WhenCalled(() => |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> WebOperationContext.Current.IncomingRequest.UserAgent) |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> .WillReturn(<span style="color: #006080">"MyAgent"</span>); |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> |
Later in the code a new channel was created using WebChannelFactory:
1 |
<span id="lnum1" style="color: #606060"> 1:</span> <span style="color: #0000ff">using</span> (var wcf = <span style="color: #0000ff">new</span> WebChannelFactory<MyServer>(<span style="color: #0000ff">new</span> Uri(baseAddress))) |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> { |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> MyServer channel = wcf.CreateChannel(); |
1 |
<span id="lnum4" style="color: #606060"> 4:</span> var stream = channel.GetData(10, 10); |
1 |
<span id="lnum5" style="color: #606060"> 5:</span> } |
1 |
<span id="lnum6" style="color: #606060"> 6:</span> |
And then something strange happened – the test failed because WCF has thrown a NullReferenceException from code that seemed to have absolutely nothing to do with the simple behavior we’ve set.
It seemed that when we’ve set behavior we’ve also accidentally set WebOPerationContext.Currect to always return a fake object. later on WCF framework tried to set or get some value from the current context and received null instead.
This seemed to be a tricky problem – how do we set the return value on UserAgent without faking the current context while doing so?
This can be done by replacing Isolate.WhenCalled with the following lines:
1 |
<span id="lnum1" style="color: #606060"> 1:</span> var fakeContext = Isolate.Fake.Instance<WebOperationContext>(Members.CallOriginal, ConstructorWillBe.Ignored); |
1 |
<span id="lnum2" style="color: #606060"> 2:</span> Isolate.WhenCalled(() => fakeCurrent.IncomingRequest.UserAgent).WillReturn(<span style="color: #006080">"MyAgent"</span>); |
1 |
<span id="lnum3" style="color: #606060"> 3:</span> Isolate.Swap.NextInstance<WebOperationContext>().With(fakeContext); |
- Create a fake WebOperationContext that will call its original methods but not call its constructor
- Set the desired behavior – return “MyAgent”
- Tell Isolator to swap the next instance created with the fake context
What we did is to provide WCF with a “mostly working” WebOperationContext he can use while still setting the desired method to return the value we need for out test to pass