From 38b5696738b3db3ecf89093b52e324a5c7e3f9b9 Mon Sep 17 00:00:00 2001 From: Gary Roumanis Date: Thu, 14 Jun 2018 17:02:56 -0700 Subject: [PATCH] Add solo test and group (#881) --- CHANGELOG.md | 6 ++++ lib/src/backend/declarer.dart | 25 ++++++++++++-- lib/test.dart | 24 ++++++++++--- pubspec.yaml | 2 +- test/runner/solo_test.dart | 64 +++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 test/runner/solo_test.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index a270b5a70..6120a6cf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.12.42 + +* Add support for `solo` test and group. When the argument is `true` only tests + and groups marked as solo will be run. It is still recommended that users + instead filter their tests by using the runner argument `-n`. + ## 0.12.41 * Add support for debugging VM tests. diff --git a/lib/src/backend/declarer.dart b/lib/src/backend/declarer.dart index d3e11fa8e..b86186dec 100644 --- a/lib/src/backend/declarer.dart +++ b/lib/src/backend/declarer.dart @@ -80,6 +80,12 @@ class Declarer { /// Whether [build] has been called for this declarer. bool _built = false; + /// The tests and/or groups that have been flagged as solo. + final _soloEntries = new Set(); + + /// Whether any tests and/or groups have been flagged as solo. + bool get _solo => _soloEntries.isNotEmpty; + /// The current zone-scoped declarer. static Declarer get current => Zone.current[#test.declarer] as Declarer; @@ -127,7 +133,8 @@ class Declarer { skip, Map onPlatform, tags, - int retry}) { + int retry, + bool solo = false}) { _checkNotBuilt("test"); var newMetadata = new Metadata.parse( @@ -164,6 +171,10 @@ class Declarer { // useful errors when calling `test()` and `group()` within a test. zoneValues: {#test.declarer: this}); }, trace: _collectTraces ? new Trace.current(2) : null, guarded: false)); + + if (solo) { + _soloEntries.add(_entries.last); + } } /// Creates a group of tests. @@ -173,7 +184,8 @@ class Declarer { skip, Map onPlatform, tags, - int retry}) { + int retry, + bool solo = false}) { _checkNotBuilt("group"); var newMetadata = new Metadata.parse( @@ -197,6 +209,10 @@ class Declarer { throw new ArgumentError("Groups may not be async."); }); _entries.add(declarer.build()); + + if (solo || declarer._solo) { + _soloEntries.add(_entries.last); + } } /// Returns [name] prefixed with this declarer's group name. @@ -240,7 +256,10 @@ class Declarer { _checkNotBuilt("build"); _built = true; - return new Group(_name, _entries.toList(), + var entries = _entries.toList(); + if (_solo) entries.removeWhere((entry) => !_soloEntries.contains(entry)); + + return new Group(_name, entries, metadata: _metadata, trace: _trace, setUpAll: _setUpAll, diff --git a/lib/test.dart b/lib/test.dart index 2712bd3ec..60d75cf19 100644 --- a/lib/test.dart +++ b/lib/test.dart @@ -132,6 +132,12 @@ Declarer get _declarer { /// /// If multiple platforms match, the annotations apply in order as through /// they were in nested groups. +/// +/// If the `solo` flag is `true`, only tests and groups marked as +/// "solo" will be be run. This only restricts tests *within this test +/// suite*—tests in other suites will run as normal. We recommend that users +/// avoid this flag if possible and instead use the test runner flag `-n` to +/// filter tests by name. @isTest void test(description, body(), {String testOn, @@ -139,14 +145,16 @@ void test(description, body(), skip, tags, Map onPlatform, - int retry}) { + int retry, + @deprecated bool solo = false}) { _declarer.test(description.toString(), body, testOn: testOn, timeout: timeout, skip: skip, onPlatform: onPlatform, tags: tags, - retry: retry); + retry: retry, + solo: solo); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and @@ -202,6 +210,12 @@ void test(description, body(), /// /// If multiple platforms match, the annotations apply in order as through /// they were in nested groups. +/// +/// If the `solo` flag is `true`, only tests and groups marked as +/// "solo" will be be run. This only restricts tests *within this test +/// suite*—tests in other suites will run as normal. We recommend that users +/// avoid this flag if possible, and instead use the test runner flag `-n` to +/// filter tests by name. @isTestGroup void group(description, body(), {String testOn, @@ -209,14 +223,16 @@ void group(description, body(), skip, tags, Map onPlatform, - int retry}) { + int retry, + @deprecated bool solo = false}) { _declarer.group(description.toString(), body, testOn: testOn, timeout: timeout, skip: skip, tags: tags, onPlatform: onPlatform, - retry: retry); + retry: retry, + solo: solo); // Force dart2js not to inline this function. We need it to be separate from // `main()` in JS stack traces in order to properly determine the line and diff --git a/pubspec.yaml b/pubspec.yaml index 61ff58931..514d3b0da 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: test -version: 0.12.41 +version: 0.12.42-dev author: Dart Team description: A library for writing dart unit tests. homepage: https://github.com/dart-lang/test diff --git a/test/runner/solo_test.dart b/test/runner/solo_test.dart new file mode 100644 index 000000000..e60eb5ead --- /dev/null +++ b/test/runner/solo_test.dart @@ -0,0 +1,64 @@ +// Copyright (c) 2018, 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("only runs the tests marked as solo", () async { + await d.file("test.dart", """ + import 'dart:async'; + + import 'package:test/test.dart'; + + void main() { + test("passes", () { + expect(true, isTrue); + }, solo: true); + test("failed", () { + throw 'some error'; + }); + } + """).create(); + + var test = await runTest(["test.dart"]); + expect(test.stdout, emitsThrough(contains("+1: All tests passed!"))); + await test.shouldExit(0); + }); + + test("only runs groups marked as solo", () async { + await d.file("test.dart", """ + import 'dart:async'; + + import 'package:test/test.dart'; + + void main() { + group('solo', () { + test("first pass", () { + expect(true, isTrue); + }); + test("second pass", () { + expect(true, isTrue); + }); + }, solo: true); + group('no solo', () { + test("failure", () { + throw 'some error'; + }); + test("another failure", () { + throw 'some error'; + }); + }); + } + """).create(); + + var test = await runTest(["test.dart"]); + expect(test.stdout, emitsThrough(contains("+2: All tests passed!"))); + await test.shouldExit(0); + }); +}