Sunday, July 28, 2013

Getting Started with Scheduled Tests in Dart


That Robert guy has loads of good ideas. One of his suggestions was to investigate the scheduled_test package for better async testing. I rather like the async testing that comes built into the unittest package in Dart, but if there is something better, then I would love to give it a whirl.

So I add scheduled_test to the list of packages my testing library is depending on:
name: plummbur_kruk
description: A real pretend server for testing.
dependencies:
  scheduled_test: any
  # ...
In the list of dependencies, scheduled_test replaces unittest. It is not a drop-in replacement for unittest. Rather, it is built on top of unittest (and replaces a few unittest methods). As such, scheduled_test depends on unittest so unittest will still be installed by Pub.

Then, I Pub install to get started:
➜  plummbur-kruk git:(master) ✗ pub install
Resolving dependencies.................
Downloading stack_trace 0.6.5 from hosted...
Downloading path 0.6.5 from hosted...
Downloading scheduled_test 0.6.5 from hosted...
Downloading http 0.6.5 from hosted...
Dependencies installed!
Now to kick the tires. I replace the import of unittest with the scheduled test equivalent:
import 'package:scheduled_test/scheduled_test.dart';
The two packages both define some of the same top-level methods so they cannot both be imported.

In the existing unittest tests, I have setup and teardown for some of my test server implementation that looks like the following in vanilla unittest:
  group("Running Server", (){
    var server;
    setUp((){
      return PlumburKruk.main()
        ..then((s){ server = s; });
    });

    tearDown(() => server.close());
    // tests here...
  });
Let's see what they might look in scheduled tests:
  group("Running Server", (){
    var server;
    setUp((){
      schedule(() {
        return PlumburKruk.main()
          .then((s){ server = s; });
      });

      currentSchedule.
        onComplete.
        schedule(() => server.close());
    });
    // tests here...
  });
That is not much of an improvement, but I am just getting familiar with things so I will defer judging for now. The big thing that has changed in the switch from a teardown function to defining the “tear down” as what happens when the scheduled tests complete.

As for the testing, I need to add something to the “schedule” in there as well. Currently, I have an asynchronous test that verifies that stub resources can be created on the server:
    test("POST /stub responds successfully", (){
      new HttpClient().
        postUrl(Uri.parse("http://localhost:31337/stub")).
        then((request) {
          request.write('{"foo": 42}');
          return request.close();
        }).
        then(expectAsync1(
           (response) {
             expect(response.statusCode, 204);
           }
        ));
    });
The asynchronous behavior occurs at the end of that test. The response from the server comes back out of band, which is what the expectAsync1() call does. It expects an asynchronous callback to be invoked at some point in the future with a single argument (the response).

There is no expectAsync in scheduled tests. Instead, I have to wrapAsync() in a schedule:
    test("POST /stub responds successfully", (){
      schedule(() {
        new HttpClient().
          postUrl(Uri.parse("http://localhost:31337/stub")).
          then((request) {
            request.write('{"foo": 42}');
            return request.close();
          }).
          then(wrapAsync(
            (response) {
              expect(response.statusCode, 204);
            }
          ));
      });
    });
I do like the wrapAsync() call instead of the expectAsyncN() methods. I am used to the variations of the latter by now, but still find it hard to explain. Conceptually, wrapAsync() is simpler.

I am not sure that I see too much value in the added ceremony of declaring new schedules. Then again I think this is probably too simple a case to see significant benefits of this package. I am mostly going through this exercise to see if I want to base significant development on scheduled tests or if the vanilla tests will suffice. So far, I like it enough to continue playing another night.


Day #826

No comments:

Post a Comment