diff --git a/pkgs/test/test/runner/configuration/randomize_order_test.dart b/pkgs/test/test/runner/configuration/randomize_order_test.dart
new file mode 100644
index 0000000000000000000000000000000000000000..537db9cf3ba2f5919418c694580fc26e6810d29e
--- /dev/null
+++ b/pkgs/test/test/runner/configuration/randomize_order_test.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2016, 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.
+
+@TestOn("vm")
+
+import 'package:test_descriptor/test_descriptor.dart' as d;
+
+import 'package:test/test.dart';
+
+import '../../io.dart';
+
+void main() {
+  test("shuffles test order when passed a seed", () async {
+    await d.file("test.dart", """
+      import 'package:test/test.dart';
+
+      void main() {
+        test("test 1", () {});
+        test("test 2", () {});
+        test("test 3", () {});
+        test("test 4", () {});
+      }
+    """).create();
+
+    // Test with a given seed
+    var test =
+        await runTest(["test.dart", "--test-randomize-ordering-seed=987654"]);
+    expect(
+        test.stdout,
+        containsInOrder([
+          "+0: test 4",
+          "+1: test 3",
+          "+2: test 1",
+          "+3: test 2",
+          "+4: All tests passed!"
+        ]));
+    await test.shouldExit(0);
+
+    // Do not shuffle when passed 0
+    test = await runTest(["test.dart", "--test-randomize-ordering-seed=0"]);
+    expect(
+        test.stdout,
+        containsInOrder([
+          "+0: test 1",
+          "+1: test 2",
+          "+2: test 3",
+          "+3: test 4",
+          "+4: All tests passed!"
+        ]));
+    await test.shouldExit(0);
+
+    // Do not shuffle when passed nothing
+    test = await runTest(["test.dart"]);
+    expect(
+        test.stdout,
+        containsInOrder([
+          "+0: test 1",
+          "+1: test 2",
+          "+2: test 3",
+          "+3: test 4",
+          "+4: All tests passed!"
+        ]));
+    await test.shouldExit(0);
+
+    // Shuffle when passed random
+    test =
+        await runTest(["test.dart", "--test-randomize-ordering-seed=random"]);
+    expect(
+        test.stdout,
+        emitsInAnyOrder([
+          contains("Shuffling test order with --test-randomize-ordering-seed"),
+          isNot(contains(
+              "Shuffling test order with --test-randomize-ordering-seed=0"))
+        ]));
+    await test.shouldExit(0);
+  });
+
+  test("shuffles each suite with the same seed", () async {
+    await d.file("1_test.dart", """
+      import 'package:test/test.dart';
+
+      void main() {
+        test("test 1.1", () {});
+        test("test 1.2", () {});
+        test("test 1.3", () {});
+      }
+    """).create();
+
+    await d.file("2_test.dart", """
+      import 'package:test/test.dart';
+
+      void main() {
+        test("test 2.1", () {});
+        test("test 2.2", () {});
+        test("test 2.3", () {});
+      }
+    """).create();
+
+    var test = await runTest([".", "--test-randomize-ordering-seed=12345"]);
+    expect(
+        test.stdout,
+        emitsInAnyOrder([
+          containsInOrder([
+            "./1_test.dart: test 1.2",
+            "./1_test.dart: test 1.3",
+            "./1_test.dart: test 1.1"
+          ]),
+          containsInOrder([
+            "./2_test.dart: test 2.2",
+            "./2_test.dart: test 2.3",
+            "./2_test.dart: test 2.1"
+          ]),
+          contains("+6: All tests passed!")
+        ]));
+    await test.shouldExit(0);
+  });
+
+  test("shuffles groups as well as tests in groups", () async {
+    await d.file("test.dart", """
+      import 'package:test/test.dart';
+
+      void main() {
+      group("Group 1", () {
+        test("test 1.1", () {});
+        test("test 1.2", () {});
+        test("test 1.3", () {});
+        test("test 1.4", () {});
+       });
+      group("Group 2", () {
+        test("test 2.1", () {});
+        test("test 2.2", () {});
+        test("test 2.3", () {});
+        test("test 2.4", () {});
+       }); 
+      }
+    """).create();
+
+    // Test with a given seed
+    var test =
+        await runTest(["test.dart", "--test-randomize-ordering-seed=123"]);
+    expect(
+        test.stdout,
+        containsInOrder([
+          "+0: Group 2 test 2.4",
+          "+1: Group 2 test 2.2",
+          "+2: Group 2 test 2.1",
+          "+3: Group 2 test 2.3",
+          "+4: Group 1 test 1.4",
+          "+5: Group 1 test 1.2",
+          "+6: Group 1 test 1.1",
+          "+7: Group 1 test 1.3",
+          "+8: All tests passed!"
+        ]));
+    await test.shouldExit(0);
+  });
+
+  test("shuffles nested groups", () async {
+    await d.file("test.dart", """
+      import 'package:test/test.dart';
+
+      void main() {
+      group("Group 1", () {
+        test("test 1.1", () {});
+        test("test 1.2", () {});
+        group("Group 2", () {
+          test("test 2.3", () {});
+          test("test 2.4", () {});
+        });
+       });
+      }
+    """).create();
+
+    var test =
+        await runTest(["test.dart", "--test-randomize-ordering-seed=123"]);
+    expect(
+        test.stdout,
+        containsInOrder([
+          "+0: Group 1 test 1.1",
+          "+1: Group 1 Group 2 test 2.4",
+          "+2: Group 1 Group 2 test 2.3",
+          "+3: Group 1 test 1.2",
+          "+4: All tests passed!"
+        ]));
+    await test.shouldExit(0);
+  });
+}
diff --git a/pkgs/test/test/runner/configuration/suite_test.dart b/pkgs/test/test/runner/configuration/suite_test.dart
index 7d923dc5b6f78603c4e413fd43c7ffd775e81366..bc9f3a73dc64065a2d92f5047340b6af441bc2ad 100644
--- a/pkgs/test/test/runner/configuration/suite_test.dart
+++ b/pkgs/test/test/runner/configuration/suite_test.dart
@@ -20,6 +20,7 @@ void main() {
         expect(merged.runSkipped, isFalse);
         expect(merged.precompiledPath, isNull);
         expect(merged.runtimes, equals([Runtime.vm.identifier]));
+        expect(merged.testRandomizeOrderingSeed, 0);
       });
 
       test("if only the old configuration's is defined, uses it", () {
@@ -41,11 +42,13 @@ void main() {
             jsTrace: true,
             runSkipped: true,
             precompiledPath: "/tmp/js",
+            testRandomizeOrderingSeed: 1234,
             runtimes: [RuntimeSelection(Runtime.chrome.identifier)]));
 
         expect(merged.jsTrace, isTrue);
         expect(merged.runSkipped, isTrue);
         expect(merged.precompiledPath, equals("/tmp/js"));
+        expect(merged.testRandomizeOrderingSeed, 1234);
         expect(merged.runtimes, equals([Runtime.chrome.identifier]));
       });
 
diff --git a/pkgs/test/test/runner/runner_test.dart b/pkgs/test/test/runner/runner_test.dart
index 2359b0b035c1f4f6725e4cd307f8555e6908976d..0856380a4e5adf75de3f353f3b832c6a349eefd8 100644
--- a/pkgs/test/test/runner/runner_test.dart
+++ b/pkgs/test/test/runner/runner_test.dart
@@ -49,76 +49,80 @@ void main() {
 
 final _defaultConcurrency = math.max(1, Platform.numberOfProcessors ~/ 2);
 
-final _browsers = "[vm (default), chrome, phantomjs, firefox" +
-    (Platform.isMacOS ? ", safari" : "") +
-    (Platform.isWindows ? ", ie" : "") +
-    ", node]";
-
 final _usage = """
 Usage: pub run test [files or directories...]
 
--h, --help                        Shows this usage information.
-    --version                     Shows the package's version.
+-h, --help                            Shows this usage information.
+    --version                         Shows the package's version.
 
 ======== Selecting Tests
--n, --name                        A substring of the name of the test to run.
-                                  Regular expression syntax is supported.
-                                  If passed multiple times, tests must match all substrings.
+-n, --name                            A substring of the name of the test to run.
+                                      Regular expression syntax is supported.
+                                      If passed multiple times, tests must match all substrings.
 
--N, --plain-name                  A plain-text substring of the name of the test to run.
-                                  If passed multiple times, tests must match all substrings.
+-N, --plain-name                      A plain-text substring of the name of the test to run.
+                                      If passed multiple times, tests must match all substrings.
 
--t, --tags                        Run only tests with all of the specified tags.
-                                  Supports boolean selector syntax.
+-t, --tags                            Run only tests with all of the specified tags.
+                                      Supports boolean selector syntax.
 
--x, --exclude-tags                Don't run tests with any of the specified tags.
-                                  Supports boolean selector syntax.
+-x, --exclude-tags                    Don't run tests with any of the specified tags.
+                                      Supports boolean selector syntax.
 
-    --[no-]run-skipped            Run skipped tests instead of skipping them.
+    --[no-]run-skipped                Run skipped tests instead of skipping them.
 
 ======== Running Tests
--p, --platform                    The platform(s) on which to run the tests.
-                                  $_browsers
-
--P, --preset                      The configuration preset(s) to use.
--j, --concurrency=<threads>       The number of concurrent test suites run.
-                                  (defaults to "$_defaultConcurrency")
-
-    --total-shards                The total number of invocations of the test runner being run.
-    --shard-index                 The index of this test runner invocation (of --total-shards).
-    --pub-serve=<port>            The port of a pub serve instance serving "test/".
-    --timeout                     The default test timeout. For example: 15s, 2x, none
-                                  (defaults to "30s")
-
-    --pause-after-load            Pauses for debugging before any tests execute.
-                                  Implies --concurrency=1, --debug, and --timeout=none.
-                                  Currently only supported for browser tests.
-
-    --debug                       Runs the VM and Chrome tests in debug mode.
-    --coverage=<directory>        Gathers coverage and outputs it to the specified directory.
-                                  Implies --debug.
-
-    --[no-]chain-stack-traces     Chained stack traces to provide greater exception details
-                                  especially for asynchronous code. It may be useful to disable
-                                  to provide improved test performance but at the cost of
-                                  debuggability.
-                                  (defaults to on)
-
-    --no-retry                    Don't re-run tests that have retry set.
+-p, --platform                        The platform(s) on which to run the tests.
+                                      $_browsers
+
+-P, --preset                          The configuration preset(s) to use.
+-j, --concurrency=<threads>           The number of concurrent test suites run.
+                                      (defaults to "$_defaultConcurrency")
+
+    --total-shards                    The total number of invocations of the test runner being run.
+    --shard-index                     The index of this test runner invocation (of --total-shards).
+    --pub-serve=<port>                The port of a pub serve instance serving "test/".
+    --timeout                         The default test timeout. For example: 15s, 2x, none
+                                      (defaults to "30s")
+
+    --pause-after-load                Pauses for debugging before any tests execute.
+                                      Implies --concurrency=1, --debug, and --timeout=none.
+                                      Currently only supported for browser tests.
+
+    --debug                           Runs the VM and Chrome tests in debug mode.
+    --coverage=<directory>            Gathers coverage and outputs it to the specified directory.
+                                      Implies --debug.
+
+    --[no-]chain-stack-traces         Chained stack traces to provide greater exception details
+                                      especially for asynchronous code. It may be useful to disable
+                                      to provide improved test performance but at the cost of
+                                      debuggability.
+                                      (defaults to on)
+
+    --no-retry                        Don't re-run tests that have retry set.
+    --test-randomize-ordering-seed    If positive, use this as a seed to randomize the execution
+                                      of test cases (must be a 32bit unsigned integer).
+                                      If "random", pick a random seed to use.
+                                      If 0 or not set, do not randomize test case execution order.
 
 ======== Output
--r, --reporter                    The runner used to print test results.
+-r, --reporter                        The runner used to print test results.
 
-          [compact]               A single line, updated continuously.
-          [expanded] (default)    A separate line for each update.
-          [json]                  A machine-readable format (see https://goo.gl/gBsV1a).
+          [compact]                   A single line, updated continuously.
+          [expanded] (default)        A separate line for each update.
+          [json]                      A machine-readable format (see https://goo.gl/gBsV1a).
 
-    --verbose-trace               Whether to emit stack traces with core library frames.
-    --js-trace                    Whether to emit raw JavaScript stack traces for browser tests.
-    --[no-]color                  Whether to use terminal colors.
-                                  (auto-detected by default)
+    --verbose-trace                   Whether to emit stack traces with core library frames.
+    --js-trace                        Whether to emit raw JavaScript stack traces for browser tests.
+    --[no-]color                      Whether to use terminal colors.
+                                      (auto-detected by default)
 """;
 
+final _browsers = "[vm (default), chrome, phantomjs, firefox" +
+    (Platform.isMacOS ? ", safari" : "") +
+    (Platform.isWindows ? ", ie" : "") +
+    ", node]";
+
 void main() {
   test("prints help information", () async {
     var test = await runTest(["--help"]);
diff --git a/pkgs/test_core/CHANGELOG.md b/pkgs/test_core/CHANGELOG.md
index 01601e24998716fafd8ebc9f92cad8ecc37bd478..ad302826b8a78e0721c3deb644273c4398803a26 100644
--- a/pkgs/test_core/CHANGELOG.md
+++ b/pkgs/test_core/CHANGELOG.md
@@ -1,6 +1,8 @@
 ## 0.2.15-dev
 
 * Add a `StringSink` argument to reporters to prepare for reporting to a file.
+* Add --test-randomize-ordering-seed` argument to randomize test
+execution order based on a provided seed
 
 ## 0.2.14
 
diff --git a/pkgs/test_core/lib/src/runner/configuration.dart b/pkgs/test_core/lib/src/runner/configuration.dart
index f1df78f466a53fd1047b1ba8042234772b88008d..26f0c62407c9be352ba82b58857bf39abf04f07c 100644
--- a/pkgs/test_core/lib/src/runner/configuration.dart
+++ b/pkgs/test_core/lib/src/runner/configuration.dart
@@ -249,6 +249,7 @@ class Configuration {
       BooleanSelector excludeTags,
       Map<BooleanSelector, SuiteConfiguration> tags,
       Map<PlatformSelector, SuiteConfiguration> onPlatform,
+      int testRandomizeOrderingSeed,
 
       // Test-level configuration
       Timeout timeout,
@@ -294,6 +295,7 @@ class Configuration {
             excludeTags: excludeTags,
             tags: tags,
             onPlatform: onPlatform,
+            testRandomizeOrderingSeed: testRandomizeOrderingSeed,
 
             // Test-level configuration
             timeout: timeout,
@@ -539,6 +541,7 @@ class Configuration {
       BooleanSelector excludeTags,
       Map<BooleanSelector, SuiteConfiguration> tags,
       Map<PlatformSelector, SuiteConfiguration> onPlatform,
+      int testRandomizeOrderingSeed,
 
       // Test-level configuration
       Timeout timeout,
@@ -580,6 +583,7 @@ class Configuration {
             excludeTags: excludeTags,
             tags: tags,
             onPlatform: onPlatform,
+            testRandomizeOrderingSeed: testRandomizeOrderingSeed,
             timeout: timeout,
             verboseTrace: verboseTrace,
             chainStackTraces: chainStackTraces,
diff --git a/pkgs/test_core/lib/src/runner/configuration/args.dart b/pkgs/test_core/lib/src/runner/configuration/args.dart
index e0150f36763e236c13a2ccd5603c96e2ff4979df..0d04fdbac8ac91e3c75d49a897cb6f43f959a036 100644
--- a/pkgs/test_core/lib/src/runner/configuration/args.dart
+++ b/pkgs/test_core/lib/src/runner/configuration/args.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:io';
+import 'dart:math';
 
 import 'package:args/args.dart';
 import 'package:boolean_selector/boolean_selector.dart';
@@ -105,6 +106,11 @@ final ArgParser _parser = (() {
       help: "Don't re-run tests that have retry set.",
       defaultsTo: false,
       negatable: false);
+  parser.addOption("test-randomize-ordering-seed",
+      help: 'If positive, use this as a seed to randomize the execution\n'
+          'of test cases (must be a 32bit unsigned integer).\n'
+          'If "random", pick a random seed to use.\n'
+          'If 0 or not set, do not randomize test case execution order.\n');
 
   var reporterDescriptions = <String, String>{};
   for (var reporter in allReporters.keys) {
@@ -204,6 +210,17 @@ class _Parser {
       }
     }
 
+    var testRandomizeOrderingSeed =
+        _parseOption('test-randomize-ordering-seed', (value) {
+      var seed = value == 'random'
+          ? Random().nextInt(4294967295)
+          : int.parse(value).toUnsigned(32);
+      if (seed != null && seed > 0) {
+        print('Shuffling test order with --test-randomize-ordering-seed=$seed');
+      }
+      return seed;
+    });
+
     return Configuration(
         help: _ifParsed('help'),
         version: _ifParsed('version'),
@@ -233,7 +250,8 @@ class _Parser {
         paths: _options.rest.isEmpty ? null : _options.rest,
         includeTags: includeTags,
         excludeTags: excludeTags,
-        noRetry: _ifParsed('no-retry'));
+        noRetry: _ifParsed('no-retry'),
+        testRandomizeOrderingSeed: testRandomizeOrderingSeed);
   }
 
   /// Returns the parsed option for [name], or `null` if none was parsed.
diff --git a/pkgs/test_core/lib/src/runner/engine.dart b/pkgs/test_core/lib/src/runner/engine.dart
index c0f922de4cd40c5f22a4dcbc873b74aa073375c2..812d7a84c27737b182a1bb29466a6097c43dfb2d 100644
--- a/pkgs/test_core/lib/src/runner/engine.dart
+++ b/pkgs/test_core/lib/src/runner/engine.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 import 'dart:collection';
+import 'dart:math';
 
 import 'package:async/async.dart' hide Result;
 import 'package:collection/collection.dart';
@@ -320,7 +321,13 @@ class Engine {
       }
 
       if (!_closed && setUpAllSucceeded) {
-        for (var entry in group.entries) {
+        // shuffle the group entries
+        var entries = group.entries.toList();
+        if (suiteConfig.testRandomizeOrderingSeed > 0) {
+          entries.shuffle(Random(suiteConfig.testRandomizeOrderingSeed));
+        }
+
+        for (var entry in entries) {
           if (_closed) return;
 
           if (entry is Group) {
diff --git a/pkgs/test_core/lib/src/runner/suite.dart b/pkgs/test_core/lib/src/runner/suite.dart
index 0421605e8bfae582f594a83505185df25882c922..08c6ab45ccc878e15fa4614c0cf621b8d1ced7d9 100644
--- a/pkgs/test_core/lib/src/runner/suite.dart
+++ b/pkgs/test_core/lib/src/runner/suite.dart
@@ -84,6 +84,12 @@ class SuiteConfiguration {
   /// configuration fields, but that isn't enforced.
   final Map<PlatformSelector, SuiteConfiguration> onPlatform;
 
+  /// The seed with which to shuffle the test order.
+  /// Default value is 0 if not provided and will not change the test order.
+  /// The same seed will shuffle the tests in the same way every time.
+  int get testRandomizeOrderingSeed => _testRandomizeOrderingSeed ?? 0;
+  final int _testRandomizeOrderingSeed;
+
   /// The global test metadata derived from this configuration.
   Metadata get metadata {
     if (tags.isEmpty && onPlatform.isEmpty) return _metadata;
@@ -135,6 +141,7 @@ class SuiteConfiguration {
       BooleanSelector excludeTags,
       Map<BooleanSelector, SuiteConfiguration> tags,
       Map<PlatformSelector, SuiteConfiguration> onPlatform,
+      int testRandomizeOrderingSeed,
 
       // Test-level configuration
       Timeout timeout,
@@ -156,6 +163,7 @@ class SuiteConfiguration {
         excludeTags: excludeTags,
         tags: tags,
         onPlatform: onPlatform,
+        testRandomizeOrderingSeed: testRandomizeOrderingSeed,
         metadata: Metadata(
             timeout: timeout,
             verboseTrace: verboseTrace,
@@ -183,6 +191,7 @@ class SuiteConfiguration {
       BooleanSelector excludeTags,
       Map<BooleanSelector, SuiteConfiguration> tags,
       Map<PlatformSelector, SuiteConfiguration> onPlatform,
+      int testRandomizeOrderingSeed,
       Metadata metadata})
       : _jsTrace = jsTrace,
         _runSkipped = runSkipped,
@@ -193,6 +202,7 @@ class SuiteConfiguration {
         excludeTags = excludeTags ?? BooleanSelector.none,
         tags = _map(tags),
         onPlatform = _map(onPlatform),
+        _testRandomizeOrderingSeed = testRandomizeOrderingSeed,
         _metadata = metadata ?? Metadata.empty;
 
   /// Creates a new [SuiteConfiguration] that takes its configuration from
@@ -241,6 +251,8 @@ class SuiteConfiguration {
         excludeTags: excludeTags.union(other.excludeTags),
         tags: _mergeConfigMaps(tags, other.tags),
         onPlatform: _mergeConfigMaps(onPlatform, other.onPlatform),
+        testRandomizeOrderingSeed:
+            other._testRandomizeOrderingSeed ?? _testRandomizeOrderingSeed,
         metadata: metadata.merge(other.metadata));
     return config._resolveTags();
   }
@@ -260,6 +272,7 @@ class SuiteConfiguration {
       BooleanSelector excludeTags,
       Map<BooleanSelector, SuiteConfiguration> tags,
       Map<PlatformSelector, SuiteConfiguration> onPlatform,
+      int testRandomizeOrderingSeed,
 
       // Test-level configuration
       Timeout timeout,
@@ -281,6 +294,8 @@ class SuiteConfiguration {
         excludeTags: excludeTags ?? this.excludeTags,
         tags: tags ?? this.tags,
         onPlatform: onPlatform ?? this.onPlatform,
+        testRandomizeOrderingSeed:
+            testRandomizeOrderingSeed ?? _testRandomizeOrderingSeed,
         metadata: _metadata.change(
             timeout: timeout,
             verboseTrace: verboseTrace,