Mocking the Unmockable

I last wrote about the process involved in mocking the System.Net.WebRequest abstract class to provide a way to return a WebResponse:

public static FakeWebResponse FakeResponse { get; set; }
public override WebResponse GetResponse()
{
  return (HttpWebResponse)FakeResponse;
}

You can also implement the BeginGetResponse call using Delegate.Invoke if you need to. From there, you implement your WebResponse fake:

public class FakeWebResponse : System.Net.WebResponse
{
  public FakeWebResponse()
  {
    ResponseHeaders = new WebHeaderCollection();
    StatusCode = HttpStatusCode.OK;
  }
  public WebHeaderCollection ResponseHeaders { get; set; }
  public override WebHeaderCollection Headers
  {
    get { return ResponseHeaders; }
  }
  public HttpStatusCode StatusCode { get; set; }
  // etc. Trivially implement other WebResponse members
}

This is all well and good, except that when working with HTTP, there’s one critical piece of information that’s not part of the HttpResponse class: the StatusCode member. In fact, most code I’ve seen for working with WebResponse looks like this:

pre(code)HttpWebResponse r = (HttpWebResponse)request.GetResponse();

Developers rarely bother with the abstraction to WebResponse because you almost always need to know what the HTTP status for the response is.

So this is where it gets hairy, and when I embarked on this task, I began to wonder if I wasn’t better off just giving up and using Cassini to spin up an ASP.NET server in process and use plain old HttpWebRequest. But that strategy is fraught with pain, suddenly tying you to the headache of keeping stuff on the file system, configuring a big object, maintaining out of process communications, tracking dynamic port assignments… it’s a lot of work just to get a server, and then you have to write ASPX or ASHX pages for every scenario you want to test… and then things like handling network-level errors, DNS lookup failures, or timeouts are still unsolved problems. There must be a way to do it.

The answer is in the cast operator. What we need is a way to create a HttpWebResponse if the caller actually needs one. The problem is, the constructor in question is internal, and to make matters worse, it uses several internal objects as arguments. So the short story is, it’s a pain to create an HttpWebResponse. The long story is… well, (sigh)…

public static explicit operator HttpWebResponse(FakeWebResponse f)
{
  HttpWebResponse result = null;
  Type crdType = typeof(HttpWebResponse).Assembly.GetType("System.Net.CoreResponseData");
  ConstructorInfo cons2 = crdType.GetConstructor(new Type[] { });
  object crd = cons2.Invoke(new object[] { });
  FieldInfo fi = crdType.GetField("m_ConnectStream");
  fi.SetValue(crd,f.ResponseStream);
  fi = crdType.GetField("m_ResponseHeaders");
  fi.SetValue(crd, f.ResponseHeaders);
  fi = crdType.GetField("m_StatusCode");
  fi.SetValue(crd,f.StatusCode);
  Type khvType = typeof(HttpWebResponse).Assembly.GetType("System.Net.KnownHttpVerb");
  ConstructorInfo khvTypeInit = khvType.TypeInitializer;
  FieldInfo getField = khvType.GetField("Get", BindingFlags.NonPublic | BindingFlags.Static);
  object getVal = getField.GetValue(null);
  ConstructorInfo cons = typeof(HttpWebResponse).GetConstructor(
                BindingFlags.NonPublic | BindingFlags.Instance,
                null,
                new [] { typeof(Uri),
                    khvType,
                    crdType,
                    typeof(String),
                    typeof(bool),
                    typeof(DecompressionMethods) },
                    null);
  return (HttpWebResponse)cons.Invoke(
                new [] { new Uri("http://localhost"), getVal, crd, "text/html", false, DecompressionMethods.None });
}

One funny thing I encountered was that I had to invoke the cast in the GetResponse() method rather than rely on the cast in the calling code – I found that my cast operator was never called, presumably because the compiler was creating a conversion from a WebResponse to HttpWebResponse. An explicit cast in GetResponse solves that:

pre(code).public override WebResponse GetResponse()
{ return (HttpWebResponse)FakeResponse;
}

Of course, this code comes with all the caveats that come with poking around in internal code: it can change in a future release, you’re mucking around in code you don’t own and Microsoft makes no promises about, etc. But it does work, and using this technique gives you a way to test that last bit of code that is going to hit all those network errors, DNS errors, timeouts, and HTTP Status codes that you need to handle.

I’m told that you could just spend the money on TypeMock Isolator and have all this work done for you, and that kind of power may well be worth the cost – provided you don’t use it as a crutch to avoid addressing design problems in code you control. But if you want a way to do it on the cheap, the cast operator and a bit of reflection will get you there.

— Gordon Weakliem

Comment

---

Channeling John Malkovich

One of the frustrations of working with the .NET Framework is the framework engineers’ practice of favoring encapsulation over testability. System.Net.WebRequest and its cohorts are a great example. On the one hand, these classes are a good example of a well-encapsulated design; using a factory pattern for instantiation; and branching off a number of useful subclasses from the base, such as System.Net.HttpWebRequest and System.Net.FtpWebRequest. The WebRequest family implements connection management, authorization, SSL connections, an optional asynchronous programming model, and a variety of other features. Aside from a few quirks and edge cases, it’s a fine class.

Except when it comes to testing.

I will not be mocked

The essential problem is that there isn’t any way to just create a WebRequest and pass it to your object. The classic way to isolate dependencies would be use a Dependency Injection pattern to pass an interface to the target object so you could construct it with a real instance or some sort of fake for testing purposes. But construction is done through a factory, so that option’s off the table, at least at some level – at the point you create a WebRequest, you have to do it through WebRequest.Create

A bit of research reveals that there’s a way to get into the factory, however: WebRequest.RegisterPrefix allows one to register a factory class to create WebRequests for a given protocol spec, e.g.

// urls beginning with mock:// will be StubWebRequests
WebRequest.RegisterPrefix("mock", new StubWebRequest.StubWebRequestCreate());
WebRequest req = WebRequest.Create("mock://something"); 
// req is StubWebRequest

So, from there it’s a SMOP to implement a factory that creates a StubWebRequest:

public class StubWebRequest : WebRequest
{
 public class StubWebRequestCreate : IWebRequestCreate
 {
    public WebRequest Create(Uri uri)
    {
      return new StubWebRequest(uri);
    }
 }
 public override string Method { get; set; }
 public override string ContentType { get; set; }
 // etc... Implement other members here
}

This works well, as far as getting your fake WebRequest created and injected into your code. But what if you want more of a Mock object, that acts like a WebRequest, to the point of responding to GetResponse() / BeginGetResponse(AsyncCallback,object). Then the story takes on a few twists.

— Gordon Weakliem

Comment

---

On the Other Foot

Jon Gruber says that “For a perfect game I say you give the pitcher the call on a truly close play”. Many people want Major League Baseball to overturn the blown call in Galarraga’s near-perfect game last night. What I have to wander about the Joyce blunder is this: suppose Joyce blew the call the other way, and the runner was clearly out by a full step, and yet was called safe? Should the pitcher be stripped of the perfect game? Seriously, there’d be some griping, but not nearly the outcry to reverse the call. You take the fact that a guy has a career best moment taken away by a blown call, and not just any blown call, the last out of the game. It’s a dramatic story, and had the call been blown in Galarraga’s favor, it’s nowhere near as dramatic.

It’s a big day for Galarraga. Maybe the biggest day of his career. I have to say though, he might end up better off now than had he been awarded the 3rd perfect game in a month, the 21st perfect game in over a century of MLB recordkeeping. Seriously, name for me just five of the 20 pitchers who’ve pitched a perfect game. People won’t forget Galarraga’s name anytime soon. I heard some commentator on the news today claiming that Galarraga would lose $100K over this – nonsense. Galarraga proved himself a class act and if anything, he’s pure gold as a sports personality right now.

— Gordon Weakliem

Comment

---

LP to Digital

I have around 150 LP records from the good old days of vinyl; some of it is music I’ve owned since high school. I was given a USB turntable for Christmas and I finally unpacked my LPs from their boxes for the first time in years and set about digitizing them. At one time my collection was two or three times that size, but I’ve sold off so much of it back when it was clear that LP was a dead format. It’s funny looking back at what I have and what I sold along the way. Some stuff I sold and now I’m buying back in digital form, other things I kept and I’m scratching my head wondering why I’ve been dragging that around for all these years.

One thing this brings back is memories of the CD vs LP arguments in the late 80’s. At the time I had a roommate who was a real audiophile, who spent serious money on his turntable, and he challenged me to a double blind test. In every case, I picked LP over CD, but in the end it didn’t matter. CDs are a lot smaller, more portable, and more versatile, and by 1990 I had all but given up on the LP format. It’s funny timing that the NY Times covered both the decline in audio quality and changes in listening habits. I don’t actively listen the way I used to. Part of it is that I’m not really a musician anymore and I don’t tend to pick apart what I’m listening to, but part of it is that I definitely have switched from music as an activity to music as an accessory.

Anyway, I’ve started the process of converting some of those old LPs to digital.
How to digitize records with Ubuntu, a USB Turntable and Audacity.

A couple of things that weren’t clear about working with Audacity:

— Gordon Weakliem

Comment

---

Taxing the Hell Out of Wall Street

Mark Cuban proposes instituting a $0.25 per share tax on stock trades. Both sides of the trade, so it’s effectively a $0.50 tax per share.

bq.If you dont think the company you are buying is worth at least a quarter more than what you are paying , why are you buying shares ?

I can see a few effects right off the bat. First of all, nobody would buy a low-priced stock. Liquidity would evaporate for anything priced under $10/share, maybe for anything undrer $25 / share. Why would you accept a 1%, or 2.5% slippage on a trade? I don’t think Cuban’s proposal has any realistic chance of being implemented, even at a penny per share, but if it were, every company on the NYSE, AMEX and NASDAQ would start doing reverse splits to get their share price to a point where you aren’t investing from a gigantic loss.

If the data in this chart are accurate, stocks on average have returned 2%-2.5% annually (before dividends but after adjusting for inflation) over the last 140 years. If that’s correct… well, you do the math.

Second, people already pay capital gains tax, but only if they make money. Cuban wants to tax the losers as well as the winners.

Finally, what would you do with the money? Cuban proposes “giving to Main Street”, but what does that mean? Institute a national dividend? Most people can’t manage money to begin with. Pay down the national debt, as some commenters proposed? A fine idea, but after the first couple years, then what? Have the Treasury play in the derivatives market. Mark Cuban must be insane. How did he get from dismissing day traders to endorsing speculation by the government? And what makes him think that the US Treasury would fare any better at speculation than, say, Lehman Brothers? What good does it do to be short the market if the other side of the contract goes bust?

In any case, we had such a system in place previously. It wasn’t that long ago that most brokerages charged $25 or more in commissions on each trade. For a hundred shares, the kind of lots that small investors work with, that’s a quarter a share. It wasn’t a tax, it just went to the brokerages’ bottom line. Cuban acts like the market’s never crashed before. So you held P&G and were down 30% at one point yesterday? If you held the stock, so what? You’re down a few percent. Cuban purports to be an investor and freaks out when the market goes totally irrational for a couple hours.

It’s a correction. If you really are a long-term investor, that means that stocks are going on sale.

— Gordon Weakliem

Comment

---

Older