Wednesday, November 25, 2015

Testing Patterns


Tonight, I start testing the code in Design Patterns in Dart. I expect my testing approach will evolve as the book is written. For now, I plan to test code used directly in the book (for obvious reasons) and some of the experimental code that I use to explore patterns before writing.

To start, I will write some tests for the Flyweight pattern coffee shop example with which I have been playing. I start by adding the test packages to the list of development dependencies in my pubspec.yaml:
name: flyweight_code
dependencies:
  reflectable: any
dev_dependencies:
  test: any
transformers:
- reflectable:
    entry_points:
      - bin/coffee_orders.dart
    formatted: true
After a pub get, I start a test/coffee_shop_test.dart file:
library coffee_shop_test;

import 'package:test/test.dart';

import 'package:flyweight_code/coffee_shop.dart';

main(){
  // Tests will go here...
}
With that, I can define some test setUp() to create my flyweight-based coffee shop and place some coffee orders:
  var shop;
  setUp((){
    shop = new CoffeeShop()
      ..order('Cappuccino', 'large', who: 'Fred', fooFoo: 'Extra Shot')
      ..order('Espresso',   'small', who: 'Bob')
      ..order('Cappuccino',     'large', who: 'Alice');
  });
I can test some of the properties of this coffee shop:
  test('it can calculate profit', (){
    expect(shop.profit, 15.2);
  });
  test('it flyweights', (){
    expect(CoffeeFlavor.totalCount, 2);
  });
The profit is based on the cost per ounce of the different coffees. The total count of coffee flavors is determined from the number of flyweight objects in use. Those are both fairly easy tests and do not take much effort to get working. Testing in Dart is still quite pleasant.

I am curious about testing print() statements. I have not had an excuse to do so in any of my Dart code to date, but I happen to use print statements in the serve() method of the coffee shop:
  void serve() {
    _orders.forEach((o) { print("Served ${o.service}.");});
  }
The service property for the orders is something like "Espresso to Bob", so I want to verify that serving drinks prints out the phrase "Served Espresso to Bob". Since there are a number of print() statements throughout the code, I need to verify that all prints contain this phrase. In test parlance, this is expressed as:
  test('prints when serving', (){
    expect(shop.serve, prints(contains('Served Espresso to Bob.')));
  });
So that turns out to be pretty easy! More importantly, the tests all pass:
$ pub run test -r expanded
00:00 +0: test/coffee_shop_test.dart: it can calculate profit
00:00 +1: test/coffee_shop_test.dart: it flyweights
00:00 +2: test/coffee_shop_test.dart: prints when serving
00:00 +3: All tests passed!
So I can test an individual patterns. Now I need to test all of them in the repository. As far as I know, this is the purview of Bash scripts. Fortunately, I have done this before:
#!/bin/bash -e

shopt -s extglob

for X in !(LICENSE|README.md|bin|packages)
do
    # Change the current working directory to pattern directory
    cd $X
    echo "[TEST] $X "

    # Update pub
    echo -n "pub update"
    pub get >/dev/null
    echo " (done)"

    # Run the actual tests
    pub run test
    echo

    # Back to the top-level directory
    cd - >/dev/null
done
This iterates over all files and directories in the repository, except for LICENSE, README.md, bin, and packages. In each code directory, it runs the tests. With that, I have a build script for my book code:
$ ./bin/test.sh
[TEST] flyweight 
pub update (done)
00:00 +3: All tests passed!
I think that I am done now with the Flyweight pattern. I may make a quick check of things tomorrow, but I am likely on to a new pattern.

Day #14


No comments:

Post a Comment