Sunday, October 27, 2013

Getting Started with Angular.dart's New Testing Features


I probably need to quit while I am ahead with Angular.dart. It is under such active development that I could spend every other night correcting posts that have been made obsolete by new releases. Between the API documentation and the Angular.dart Tutorial, I am very likely polluting the documentation pool with stuff that will be obsolete before long.

Still, it is very exciting that so much is happening with the Dart port of the AngularJS project. I fully intend to come back at some point and before I leave, I cannot resist the chance to play with the test bed that the project uses internally. Yes, I am completely obsessed with testing and, more importantly, finding new and unique ways to test.

Happily testing methods were recently exposed directly in the library, so there is no need for me to do bad things to my local copy of the repository. All of this work is done against the 0.0.6 release of the package.

I start with my test setup, which needs to establish the injector context for the test:
import 'package:unittest/unittest.dart';
import 'package:unittest/mock.dart';
import 'dart:html';
import 'dart:async';

import 'package:angular/angular.dart';
import 'package:angular/mock/module.dart';

import 'package:angular_calendar/calendar.dart';

main(){
  group('Appointment', (){
    setUp(setUpInjector);
    // ...
  });
}
The setUpInjector function is part of the angular mock library, which is already being imported.

Next, I need a module that includes a mock HTTP backend service so that I can set expectation:
    setUp(module((Module module) {
      http_backend = new MockHttpBackend();
      module
        ..value(HttpBackend, http_backend);
    }));
The module() function enables me to inject a fake HTTP backend into the test so that I do not need a real server running in the background. With the setup out of the way, I ought to be able to inject an instance of my backend service for actual testing.

And here, I am a bit stumped. I have a mock Angular module that has already injected a mock Http instance. I want to inject my backend into the test, so I try:
    test('add will POST for persistence', (){
      inject((AppointmentBackend b) { server = b; });

      http_backend.
        expectPOST('/appointments', '{"foo":42}').
        respond('{"id:"1", "foo":42}');

      server.add({'foo': 42});
    });
But that does not work. When I run the test, I get:
ERROR: Appointment Backend add will POST for persistence
  Test failed: Caught Illegal argument(s): No provider found for AppointmentBackend! (resolving AppointmentBackend) at position 0 source:
   (AppointmentBackend b) { server = b; }.
  #0      DynamicInjector.invoke.<anonymous closure> (package:di/dynamic_injector.dart:197:9)
  #1      DynamicInjector.invoke.<anonymous closure> (package:di/dynamic_injector.dart:196:9)
I am not quite sure what this means since I am importing my application code that defines this class. Ah well, I will keep at this tomorrow and hopefully figure out what I am doing wrong.

Update: Figured it out. This error is telling me that I have not injected the class into the fake Angular module that I am trying to use. I need only type(AppontmentBackend) to get the code working. The full version of the test using the new test module() and inject() is then:
  group('Appointment Backend', (){
    var server, http_backend;
    setUp(() {
      setUpInjector();

      module((Module module) {
        http_backend = new MockHttpBackend();
        module
          ..value(HttpBackend, http_backend)
          ..type(AppointmentBackend);
      });
    });

    test('add will POST for persistence', (){
      inject((AppointmentBackend b) { server = b; });

      http_backend.
        expectPOST('/appointments', '{"foo":42}').
        respond('{"id:"1", "foo":42}');

      server.add({'foo': 42});
    });
  });
I am still not sure I have the hang of this, so I will likely follow up more tomorrow.


Day #917

No comments:

Post a Comment