diff --git a/lib/src/spread_args_helper.dart b/lib/src/spread_args_helper.dart
index 41411b93780f4f2d68f4f6941dad6186b668f4f4..b3021eb26ca499e1252cd7471bfd346484f599ef 100644
--- a/lib/src/spread_args_helper.dart
+++ b/lib/src/spread_args_helper.dart
@@ -1,5 +1,12 @@
 part of unittest;
 
+const _PLACE_HOLDER = const _ArgPlaceHolder();
+
+/// Used to track unused positional args.
+class _ArgPlaceHolder {
+  const _ArgPlaceHolder();
+}
+
 /** Simulates spread arguments using named arguments. */
 // TODO(sigmund): remove this class and simply use a closure with named
 // arguments (if still applicable).
@@ -14,7 +21,7 @@ class _SpreadArgsHelper {
   bool complete;
 
   _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
-      Function isDone, String id)
+      String id, {bool isDone()})
       : this.callback = callback,
         minExpectedCalls = minExpected,
         maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
@@ -90,31 +97,49 @@ class _SpreadArgsHelper {
     }
   }
 
-  invoke0() {
-    return _guardAsync(
-        () {
-          if (shouldCallBack()) {
-            return callback();
-          }
-        },
-        after, testCase);
-  }
+  /// Returns a function that has as many required + positional arguments as
+  /// [callback] (up to a total of 6).
+  ///
+  /// Optional positional arguments are supported by using const place-holders
+  Function get func {
+    if (callback is _Func6) return _max6;
+    if (callback is _Func5) return _max5;
+    if (callback is _Func4) return _max4;
+    if (callback is _Func3) return _max3;
+    if (callback is _Func2) return _max2;
+    if (callback is _Func1) return _max1;
+    if (callback is _Func0) return _max0;
 
-  invoke1(arg1) {
-    return _guardAsync(
-        () {
-          if (shouldCallBack()) {
-            return callback(arg1);
-          }
-        },
-        after, testCase);
+    throw new ArgumentError(
+        'The callback argument has more than 6 required arguments');
   }
 
-  invoke2(arg1, arg2) {
+  /// This indirection is critical. It ensures the returned function has an
+  /// argument count of zero.
+  _max0() => _max6();
+
+  _max1([a0 = _PLACE_HOLDER]) => _max6(a0);
+
+  _max2([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER]) => _max6(a0, a1);
+
+  _max3([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER]) =>
+      _max6(a0, a1, a2);
+
+  _max4([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER,
+      a3 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3);
+
+  _max5([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER,
+      a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER]) => _max6(a0, a1, a2, a3, a4);
+
+  _max6([a0 = _PLACE_HOLDER, a1 = _PLACE_HOLDER, a2 = _PLACE_HOLDER,
+      a3 = _PLACE_HOLDER, a4 = _PLACE_HOLDER, a5 = _PLACE_HOLDER]) {
+    var args = [a0, a1, a2, a3, a4, a5];
+    args.removeWhere((a) => a == _PLACE_HOLDER);
+
     return _guardAsync(
         () {
           if (shouldCallBack()) {
-            return callback(arg1, arg2);
+            return Function.apply(callback, args);
           }
         },
         after, testCase);
@@ -131,3 +156,11 @@ class _SpreadArgsHelper {
     }
   }
 }
+
+typedef _Func0();
+typedef _Func1(a);
+typedef _Func2(a, b);
+typedef _Func3(a, b, c);
+typedef _Func4(a, b, c, d);
+typedef _Func5(a, b, c, d, e);
+typedef _Func6(a, b, c, d, e, f);
diff --git a/lib/unittest.dart b/lib/unittest.dart
index da95faecc9f03ca1ef539d431f88a8372c0f7b85..9add42c8b1bb6928ae3d3ebb81d4c20faac0975c 100644
--- a/lib/unittest.dart
+++ b/lib/unittest.dart
@@ -325,22 +325,8 @@ void solo_test(String spec, TestFunction body) {
  * bound.
  */
 Function expectAsync(Function callback,
-                     {int count: 1, int max: 0, String id}) {
-  var minArgs = _minArgs(callback);
-
-  switch(minArgs) {
-    case 0:
-      return new _SpreadArgsHelper(callback, count, max, null, id).invoke0;
-    case 1:
-      return new _SpreadArgsHelper(callback, count, max, null, id).invoke1;
-    case 2:
-      return new _SpreadArgsHelper(callback, count, max, null, id).invoke2;
-    default:
-      // _minArgs throws an argument exception if the arg count is > 2.
-      // this is just for paranoia
-      throw new StateError('Should never get here');
-  }
-}
+    {int count: 1, int max: 0, String id}) =>
+  new _SpreadArgsHelper(callback, count, max, id).func;
 
 /**
  * *Deprecated*
@@ -382,22 +368,8 @@ Function expectAsync2(Function callback,
  * identify the callback in error messages (for example if it is called
  * after the test case is complete).
  */
-Function expectAsyncUntil(Function callback, Function isDone, {String id}) {
-  var minArgs = _minArgs(callback);
-
-  switch(minArgs) {
-    case 0:
-      return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke0;
-    case 1:
-      return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke1;
-    case 2:
-      return new _SpreadArgsHelper(callback, 0, -1, isDone, id).invoke2;
-    default:
-      // _minArgs throws an argument exception if the arg count is > 2.
-      // this is just for paranoia
-      throw new StateError('Should never get here');
-  }
-}
+Function expectAsyncUntil(Function callback, bool isDone(), {String id}) =>
+    new _SpreadArgsHelper(callback, 0, -1, id, isDone: isDone).func;
 
 /**
  * *Deprecated*
@@ -770,18 +742,3 @@ Trace _getTrace(stack) {
     return frame.package != 'unittest' || frame.member != 'TestCase._runTest';
   })).terse.foldFrames((frame) => frame.package == 'unittest' || frame.isCore);
 }
-
-typedef _Func0();
-typedef _Func1(a);
-typedef _Func2(a, b);
-
-/**
- * Throws an [ArgumentError] if the callback has more than 2 required arguments.
- */
-int _minArgs(Function callback) {
-  if (callback is _Func0) return 0;
-  if (callback is _Func1) return 1;
-  if (callback is _Func2) return 2;
-  throw new ArgumentError(
-      'The callback argument has more than 2 required arguments.');
-}
diff --git a/test/missing_tick_test.dart b/test/missing_tick_test.dart
index 92ab8914704d7eac0c2491d2fbf3d1c307990fdb..19c5b8946ebf00754d92cbce4a43e308cadb1f14 100644
--- a/test/missing_tick_test.dart
+++ b/test/missing_tick_test.dart
@@ -10,7 +10,7 @@ main() {
   config.timeout = const Duration(seconds: 2);
   group('Broken', () {
     test('test that should time out', () {
-      expectAsync0(() {});
+      expectAsync(() {});
     });
   });
 }
diff --git a/test/test_utils.dart b/test/test_utils.dart
index de783bedcf09abf5b13449ad96ef732a592f9b73..783f71ba91839e7310c9a119de5fb3e36d5906c2 100644
--- a/test/test_utils.dart
+++ b/test/test_utils.dart
@@ -36,7 +36,7 @@ void shouldFail(value, Matcher matcher, expected, {bool isAsync: false}) {
     if (expected is String) {
       expect(errorString, equalsIgnoringWhitespace(expected));
     } else {
-     expect(errorString.replaceAll('\n',''), expected);
+      expect(errorString.replaceAll('\n', ''), expected);
     }
   }
 
diff --git a/test/unittest_async_exception_test.dart b/test/unittest_async_exception_test.dart
index 34298b7d275502227fa80a1d3a0ce6c024e465d3..cc351169debb8aee01d16c735e75e39e843541ba 100644
--- a/test/unittest_async_exception_test.dart
+++ b/test/unittest_async_exception_test.dart
@@ -13,8 +13,8 @@ var testName = 'async exception test';
 
 var testFunction = (_) {
   test(testName, () {
-    expectAsync0(() {});
-    _defer(() => guardAsync(() { throw "error!"; }));
+    expectAsync(() {});
+    _defer(() { throw "error!"; });
   });
 };
 
diff --git a/test/unittest_async_setup_teardown_test.dart b/test/unittest_async_setup_teardown_test.dart
index a73efc8e4b97c7174918f6b722aebf7ff4c7234d..067dbf951208a6e0bef895f968dbf3bda08224ef 100644
--- a/test/unittest_async_setup_teardown_test.dart
+++ b/test/unittest_async_setup_teardown_test.dart
@@ -19,7 +19,7 @@ var testFunction = (_) {
     tearDown(() {
       return new Future.value(0);
     });
-    test('foo1', (){});
+    test('foo1', () {});
   });
   group('good setup/bad teardown', () {
     setUp(() {
@@ -28,7 +28,7 @@ var testFunction = (_) {
     tearDown(() {
       return new Future.error("Failed to complete tearDown");
     });
-    test('foo2', (){});
+    test('foo2', () {});
   });
   group('bad setup/good teardown', () {
     setUp(() {
@@ -37,7 +37,7 @@ var testFunction = (_) {
     tearDown(() {
       return new Future.value(0);
     });
-    test('foo3', (){});
+    test('foo3', () {});
   });
   group('bad setup/bad teardown', () {
     setUp(() {
@@ -46,7 +46,7 @@ var testFunction = (_) {
     tearDown(() {
       return new Future.error("Failed to complete tearDown");
     });
-    test('foo4', (){});
+    test('foo4', () {});
   });
   // The next test is just to make sure we make steady progress
   // through the tests.
diff --git a/test/unittest_completion_test.dart b/test/unittest_completion_test.dart
index 843f9d06b2155db2b314659d40725339ad2c8362..037dee1e2a2f53821387d416d57cf5085cd4061f 100644
--- a/test/unittest_completion_test.dart
+++ b/test/unittest_completion_test.dart
@@ -14,7 +14,7 @@ var testName = 'completion test';
 var testFunction = (TestConfiguration testConfig) {
   test(testName, () {
     var _callback;
-    _callback = expectAsyncUntil0(() {
+    _callback = expectAsyncUntil(() {
       if (++testConfig.count < 10) {
         _defer(_callback);
       }
diff --git a/test/unittest_correct_callback_test.dart b/test/unittest_correct_callback_test.dart
index cd52ba060a13f5f8563b4f7edffcd1a52c6ef491..43b40eab2672f7fea8fc9a5dd61acdba1da52481 100644
--- a/test/unittest_correct_callback_test.dart
+++ b/test/unittest_correct_callback_test.dart
@@ -13,7 +13,7 @@ var testName = 'correct callback test';
 
 var testFunction = (TestConfiguration testConfig) {
   test(testName,
-      () =>_defer(expectAsync0((){ ++testConfig.count;})));
+      () =>_defer(expectAsync((){ ++testConfig.count;})));
 };
 
 var expected = buildStatusString(1, 0, 0, testName, count: 1);
diff --git a/test/unittest_excess_callback_test.dart b/test/unittest_excess_callback_test.dart
index f3876b518f69c487a76cb65fbd3f1609110dcd0f..76a3a9ee0949f0ae409c7ced0b4584fdd24f8d2f 100644
--- a/test/unittest_excess_callback_test.dart
+++ b/test/unittest_excess_callback_test.dart
@@ -13,9 +13,9 @@ var testName = 'excess callback test';
 
 var testFunction = (TestConfiguration testConfig) {
   test(testName, () {
-    var _callback0 = expectAsync0(() => ++testConfig.count);
-    var _callback1 = expectAsync0(() => ++testConfig.count);
-    var _callback2 = expectAsync0(() {
+    var _callback0 = expectAsync(() => ++testConfig.count);
+    var _callback1 = expectAsync(() => ++testConfig.count);
+    var _callback2 = expectAsync(() {
       _callback1();
       _callback1();
       _callback0();
diff --git a/test/unittest_expect_async_args_test.dart b/test/unittest_expect_async_args_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0fd7517584f9022cbb3cb2b108cf6bade02b0b66
--- /dev/null
+++ b/test/unittest_expect_async_args_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library unittestTest;
+
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testFunction = (TestConfiguration testConfig) {
+  List<int> _getArgs([a = 0, b = 0, c = 0, d = 0, e = 0, f = 0]) {
+    testConfig.count++;
+    return [a, b, c, d, e, f];
+  }
+
+  test('expect async args', () {
+    expect(expectAsync(_getArgs)(), [0, 0, 0, 0, 0, 0]);
+    expect(expectAsync(_getArgs)(5), [5, 0, 0, 0, 0, 0]);
+    expect(expectAsync(_getArgs)(1, 2, 3, 4, 5, 6), [1, 2, 3, 4, 5, 6]);
+  });
+
+  test('invoked with too many args', () {
+    expectAsync(_getArgs)(1, 2, 3, 4, 5, 6, 7);
+  });
+
+  test('created with too many args', () {
+    expectAsync((a1, a2, a3, a4, a5, a6, a7) {
+      testConfig.count++;
+    })();
+  });
+};
+
+final expected = startsWith('1:0:2:3:3:::null:expect async args::'
+    'invoked with too many args:Test failed:');
diff --git a/test/unittest_expect_async_test.dart b/test/unittest_expect_async_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a8bbde5f412a76a728e3a4157df477e59bb436be
--- /dev/null
+++ b/test/unittest_expect_async_test.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testFunction = (TestConfiguration testConfig) {
+  test('expectAsync zero params', () {
+    _defer(expectAsync(() {
+      ++testConfig.count;
+    }));
+  });
+
+  test('expectAsync 1 param', () {
+    var func = expectAsync((arg) {
+      expect(arg, 0);
+      ++testConfig.count;
+    });
+    _defer(() => func(0));
+  });
+
+  test('expectAsync 2 param', () {
+    var func = expectAsync((arg0, arg1) {
+      expect(arg0, 0);
+      expect(arg1, 1);
+      ++testConfig.count;
+    });
+    _defer(() => func(0, 1));
+  });
+
+  test('single arg to Future.catchError', () {
+    var func = expectAsync((error) {
+      expect(error, isStateError);
+      ++testConfig.count;
+    });
+
+    new Future(() {
+      throw new StateError('test');
+    }).catchError(func);
+  });
+
+  test('2 args to Future.catchError', () {
+    var func = expectAsync((error, stack) {
+      expect(error, isStateError);
+      expect(stack is StackTrace, isTrue);
+      ++testConfig.count;
+    });
+
+    new Future(() {
+      throw new StateError('test');
+    }).catchError(func);
+  });
+
+  test('zero of two optional positional args', () {
+    var func = expectAsync(([arg0 = true, arg1 = true]) {
+      expect(arg0, isTrue);
+      expect(arg1, isTrue);
+      ++testConfig.count;
+    });
+
+    _defer(() => func());
+  });
+
+  test('one of two optional positional args', () {
+    var func = expectAsync(([arg0 = true, arg1 = true]) {
+      expect(arg0, isFalse);
+      expect(arg1, isTrue);
+      ++testConfig.count;
+    });
+
+    _defer(() => func(false));
+  });
+
+  test('two of two optional positional args', () {
+    var func = expectAsync(([arg0 = true, arg1 = true]) {
+      expect(arg0, isFalse);
+      expect(arg1, isNull);
+      ++testConfig.count;
+    });
+
+    _defer(() => func(false, null));
+  });
+};
+
+final expected = '8:0:0:8:8:::null:expectAsync zero params:'
+    ':expectAsync 1 param::expectAsync 2 param:'
+    ':single arg to Future.catchError::2 args to Future.catchError:'
+    ':zero of two optional positional args:'
+    ':one of two optional positional args:'
+    ':two of two optional positional args:';
diff --git a/test/unittest_late_exception_test.dart b/test/unittest_late_exception_test.dart
index 7a5c3e61cbdb86ddfad33eb31649c6ff00c1a6f2..c80de1263329dab9e81ad440aceee9b8036db5b5 100644
--- a/test/unittest_late_exception_test.dart
+++ b/test/unittest_late_exception_test.dart
@@ -14,11 +14,11 @@ var testName = 'late exception test';
 var testFunction = (_) {
   var f;
   test('testOne', () {
-    f = expectAsync0(() {});
+    f = expectAsync(() {});
     _defer(f);
   });
   test('testTwo', () {
-    _defer(expectAsync0(() { f(); }));
+    _defer(expectAsync(() { f(); }));
   });
 };
 
diff --git a/test/unittest_middle_exception_test.dart b/test/unittest_middle_exception_test.dart
index d405500c57d05476bbd634172ccb99aab6034427..ba7751470b30046bbe22f6dd27f360ce13fb44e3 100644
--- a/test/unittest_middle_exception_test.dart
+++ b/test/unittest_middle_exception_test.dart
@@ -15,7 +15,7 @@ var testFunction = (_) {
   test('testOne', () { expect(true, isTrue); });
   test('testTwo', () { expect(true, isFalse); });
   test('testThree', () {
-    var done = expectAsync0((){});
+    var done = expectAsync(() {});
     _defer(() {
       expect(true, isTrue);
       done();
diff --git a/test/unittest_protect_async_test.dart b/test/unittest_protect_async_test.dart
index 12ded3cecd0b03be67db1b7e7ac18ba92969f018..15d339484d8f3cd63499a0fae0a02a90f8ab2a2e 100644
--- a/test/unittest_protect_async_test.dart
+++ b/test/unittest_protect_async_test.dart
@@ -11,23 +11,23 @@ part 'unittest_test_utils.dart';
 
 var testFunction = (_) {
   test('protectAsync0', () {
-    var protected = protectAsync0(() {
+    var protected = () {
       throw new StateError('error during protectAsync0');
-    });
+    };
     new Future(protected);
   });
 
   test('protectAsync1', () {
-    var protected = protectAsync1((arg) {
+    var protected = (arg) {
       throw new StateError('error during protectAsync1: $arg');
-    });
+    };
     new Future(() => protected('one arg'));
   });
 
   test('protectAsync2', () {
-    var protected = protectAsync2((arg1, arg2) {
+    var protected = (arg1, arg2) {
       throw new StateError('error during protectAsync2: $arg1, $arg2');
-    });
+    };
     new Future(() => protected('arg1', 'arg2'));
   });
 
diff --git a/test/unittest_test_returning_future_test.dart b/test/unittest_test_returning_future_test.dart
index a74a8db55479d6522cbfc9feceb136aeea82fc4a..83c4a5d3673d734333a3bb71b7a7c16f1f4b11ed 100644
--- a/test/unittest_test_returning_future_test.dart
+++ b/test/unittest_test_returning_future_test.dart
@@ -21,8 +21,8 @@ var testFunction = (_) {
   // I had a situation where either worked fine on their own, and
   // error/fail worked, but fail/error would time out.
   test("error1", () {
-    var callback = expectAsync0((){});
-    var excesscallback = expectAsync0((){});
+    var callback = expectAsync(() {});
+    var excesscallback = expectAsync(() {});
     return _defer(() {
       excesscallback();
       excesscallback();
@@ -36,8 +36,8 @@ var testFunction = (_) {
     });
   });
   test("error2", () {
-    var callback = expectAsync0((){});
-    var excesscallback = expectAsync0((){});
+    var callback = expectAsync(() {});
+    var excesscallback = expectAsync(() {});
     return _defer(() {
       excesscallback();
       excesscallback();
diff --git a/test/unittest_test_returning_future_using_runasync_test.dart b/test/unittest_test_returning_future_using_runasync_test.dart
index 98f276b825f04a9d3b8d856f1266f0ea612247b4..e5fc304d7168b80a52c06d0f9512f35a1f5d14f2 100644
--- a/test/unittest_test_returning_future_using_runasync_test.dart
+++ b/test/unittest_test_returning_future_using_runasync_test.dart
@@ -15,58 +15,48 @@ var testFunction = (_) {
   test("successful", () {
     return _defer(() {
       scheduleMicrotask(() {
-        guardAsync(() {
-          expect(true, true);
-        });
+        expect(true, true);
       });
     });
   });
   test("fail1", () {
-    var callback = expectAsync0((){});
+    var callback = expectAsync(() {});
     return _defer(() {
       scheduleMicrotask(() {
-        guardAsync(() {
-          expect(true, false);
-          callback();
-        });
+        expect(true, false);
+        callback();
       });
     });
   });
   test('error1', () {
-    var callback = expectAsync0((){});
-    var excesscallback = expectAsync0((){});
+    var callback = expectAsync(() {});
+    var excesscallback = expectAsync(() {});
     return _defer(() {
       scheduleMicrotask(() {
-        guardAsync(() {
-          excesscallback();
-          excesscallback();
-          callback();
-        });
+        excesscallback();
+        excesscallback();
+        callback();
       });
     });
   });
   test("fail2", () {
-    var callback = expectAsync0((){});
+    var callback = expectAsync(() {});
     return _defer(() {
       scheduleMicrotask(() {
-        guardAsync(() {
-          fail('failure');
-          callback();
-        });
+        fail('failure');
+        callback();
       });
     });
   });
   test('error2', () {
-    var callback = expectAsync0((){});
-    var excesscallback = expectAsync0((){});
+    var callback = expectAsync(() {});
+    var excesscallback = expectAsync(() {});
     return _defer(() {
       scheduleMicrotask(() {
-        guardAsync(() {
-          excesscallback();
-          excesscallback();
-          excesscallback();
-          callback();
-        });
+        excesscallback();
+        excesscallback();
+        excesscallback();
+        callback();
       });
     });
   });
diff --git a/test/unittest_test_utils.dart b/test/unittest_test_utils.dart
index adb9823f366111179ed0b6bc437ebc8ba7b23de9..8385a1b7b767eea7d4a658943fead7473dc7f382 100644
--- a/test/unittest_test_utils.dart
+++ b/test/unittest_test_utils.dart
@@ -16,7 +16,7 @@ String buildStatusString(int passed, int failed, int errors,
                          String message: ''}) {
   var totalTests = 0;
   var testDetails = new StringBuffer();
-  if(results == null) {
+  if (results == null) {
     // no op
     assert(message == '');
   } else if (results is String) {
@@ -44,7 +44,7 @@ class TestConfiguration extends Configuration {
   final SendPort _port;
   String _result;
 
-  TestConfiguration(this._port) : super.blank();
+  TestConfiguration(this._port): super.blank();
 
   void onSummary(int passed, int failed, int errors, List<TestCase> results,
       String uncaughtError) {
@@ -88,6 +88,6 @@ main() {
   var replyPort = new ReceivePort();
   Isolate.spawn(runTestInIsolate, replyPort.sendPort);
   replyPort.first.then((String msg) {
-    expect(msg.trim(), equals(expected));
+    expect(msg.trim(), expected);
   });
 }