Wednesday, December 26, 2012

More Mock Http Requests in Dart

‹prev | My Chain | next›

I have a hacky unit test in place for some early code from Dart for Hipsters. Rather unfortunately, this involves jamming a conditional-behavior HttpRequest class directly in production code. Ultimately, this code evolves into Hipster MVC, which allows the data sync layer to be injected as a matter of course. Testing will be easy there. But what happens when I try to test the code after the initial implementation and before the injection class? Hopefully I might learn a better way of doing this.

In the book, I move the HttpRequest code out into something of a MVC collection. The code is identical to the fully inline code used before refactoring with one small exception:
class ComicsCollection implements Collection {
  //  ...
  void fetch() {
    var req = new HttpRequest();
    req.on.load.add((event) {
      var list = JSON.parse(req.responseText);
      _handleOnLoad(list);
    });
    // verb, resource, boolean async
    req.open('get', url, true);
    req.send();
  }
}
The difference is the _handleOnLoad() private method. In the original implementation, this had simply built HTML for the page, which could be immediately tested. Now, I build a bunch of models based on the JSON and dispatch a load event:
  _handleOnLoad(list) {
    list.forEach((attrs) {
      var new_model = new ComicBook(attrs);
      new_model.collection = this;
      models.add(new_model);
    });

    on.load.dispatch(new CollectionEvent('load', this));
  }
Eventually that load event reaches the necessary view, which draws the individual elements on the page.

I can play the same trick of my code that I did yesterday, replacing HttpRequest in that fetch() method with my custom built MaybeMockHttpRequest. By default, that uses the real HttpRequest, so my sample app still runs. Some well placed setUp() code in my tests insert a fake HttpRequest and response:
    setUp((){
      Main.MaybeMockHttpRequest.use_mock = true;
      Main.MockHttpRequest.responseText = """
        [{"id":"42", "title": "Sandman", "author":"Neil Gaiman"}]
      """;

      document.body.append(el);
    });

    test('populates the list', (){
      Main.main();
      expect(el.innerHtml, contains('Sandman'));
    });
With that, I have a passing test:


It is encouraging that this MaybeMockHttpRequest approach still works in the modified code. I have a bit more confidence in sticking with this approach—at least to keep the code in my book under test.

At the same time, it still feels wrong. I should not have to resort to fake class hackery in live code just to test my code. I might claim that Dart wants dependency injected HttpRequest layers by virtue of difficulty testing any other way—I did eventually factor this code out into a testable sync layer. But that seems a cop out—I ought to be able to test vanilla HttpRequest code.

Part of the problem is definitely me. I am trying to perform (nearly) full stack integration testing with a unit testing library. Maybe I should live with a bit of hackery. Or maybe I need to embrace the insanity and fire up a test server so that I can truly test the entire stack. Tomorrow.


Day #611

1 comment: