Skip to content

Commit e259d37

Browse files
committed
Proposal for testing support in SwiftPM
1 parent d220ae4 commit e259d37

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Swift Testing
2+
3+
* Authors:
4+
[Max Howell](https://github.com/mxcl),
5+
[Daniel Dunbar](https://github.com/ddunbar),
6+
[Mattt Thompson](https://github.com/mattt)
7+
* Status: **Review**
8+
* Review Manager: Rick Ballard
9+
10+
## Introduction
11+
12+
Testing is an essential part of modern software development.
13+
Tight integration of testing into the Swift Package Manager
14+
will help ensure a stable and reliable packaging ecosystem.
15+
16+
## Proposed Solution
17+
18+
We propose to extend our conventional package directory layout
19+
to accomodate test modules.
20+
Any subdirectory of the package root directory named "Tests"
21+
or any subdirectory of an existing module directory named "Tests"
22+
will comprise a test module.
23+
For example:
24+
25+
Package
26+
├── Sources
27+
│ └── Foo
28+
│ └──Foo.swift
29+
└── Tests
30+
└── Foo
31+
└── Test.swift
32+
33+
Or:
34+
35+
Package
36+
└── Sources
37+
├── Foo.swift
38+
└── Tests
39+
└── Test.swift
40+
41+
Or, for simpler projects:
42+
43+
Package
44+
├── Sources
45+
│ └── Foo.swift
46+
└── Tests
47+
└── TestFoo.swift
48+
49+
The filename: `TestFoo.swift` is arbituary.
50+
51+
In the examples above
52+
a test case is created for the module `Foo`
53+
based on the sources in the relevant subdirectories.
54+
55+
Additionally we will support directories called `FooTests`.
56+
This layout style is prevalent in existing open source projects
57+
and supporting it will minimize vexation for their authors.
58+
However in the interest of consistency and the corresponding
59+
reduction of cognitive-load when examining new Swift packages
60+
we will not recommend this layout. For example:
61+
62+
Package
63+
└── Sources
64+
│ └── Foo.swift
65+
└── FooTests
66+
└── Test.swift
67+
68+
Additionally, we propose that building a module
69+
also builds that module's corresponding tests.
70+
Although this would result in slightly increased build times,
71+
we believe that tests are important enough to justify this
72+
(one might even consider slow building tests to be a code smell).
73+
We would prefer to go even further by executing the tests
74+
each time a module is built as well,
75+
but we understand that this would impede debug cycles.
76+
77+
As an exception, when packages are built in release mode we will
78+
not build tests because for release builds we should not enable
79+
testability. However, considering the need for release-mode testing
80+
this will be a future direction.
81+
82+
### Command-Line Interface
83+
84+
We propose the following syntax to execute tests:
85+
86+
$ swift build --test
87+
88+
Or:
89+
90+
$ swift build -t
91+
92+
In the future, we may choose to promote the `--test` option
93+
to be a subcommand of the `swift` command itself:
94+
95+
$ swift test
96+
97+
However, any such decision would warrant extensive design consideration,
98+
so as to avoid polluting or crowding the command-line interface.
99+
Should there be sufficient demand and justification for it, though,
100+
it would be straightforward to add this functionality.
101+
102+
### Command Output
103+
104+
Executing a test from the terminal will produce user-readable output.
105+
This should incorporate colorization and other formatting
106+
similar to other testing tools
107+
to indicate the success and failure of different tests.
108+
For example:
109+
110+
$ swift test --output module
111+
Running tests for PackageX (x/100)
112+
.........x.....x...................
113+
114+
Completed
115+
Elapsed time: 0.2s
116+
117+
98 Success
118+
2 Failure
119+
1 Warning
120+
121+
FAILURE: Tests/TestsA.swift:24 testFoo()
122+
XCTAssertTrue expected true, got false
123+
124+
FAILURE: Tests/TestsB.swift:10 testBar()
125+
XCTAssertEqual
126+
127+
WARNING: Tests/TestsC.swift:1
128+
"Some Warning"
129+
130+
An additional option may be passed to the testing command
131+
to output JUnit-style XML or other formats that can be integrated
132+
with continuous integration (CI) and other systems.
133+
134+
### Backwards Compatibility
135+
136+
In order to accomodate existing packages,
137+
we will allow test module targets and their targets
138+
to be overridden in the `Package.swift` manifest file.
139+
However, this functionality will likely not be implemented
140+
in the initial release of this feature,
141+
and instead be added at a later point in time.
142+
143+
### Automatic Dependency Determination
144+
145+
Testing is important and it is important to make the barrier to testing
146+
as minimal as possible. Thus, by analyzing the names of test targets,
147+
we will automatically determine the most likely dependency of that test
148+
and accomodate accordingly.
149+
For example,
150+
a test for "Foo" will depend on compilation of the library target `Foo`.
151+
Any additional dependencies or dependencies that could not be automatically determined
152+
would need to be specified in a package manifest separately.
153+
154+
### Debug / Release Configuration
155+
156+
Although tests built in debug configuration
157+
are generally run against modules also build in debug configuration,
158+
it is sometimes necessary to specify the build configuration for tests separately.
159+
It is also sometimes necessary to explicitly specify this information for every build,
160+
such as when building in a release configuration to execute performance tests.
161+
We would like to eventually support these use cases,
162+
however this will not be present in the initial implementation of this feature.
163+
164+
### Testability
165+
166+
Swift can build modules with "testability",
167+
which allows tests to access entities with `internal` access control.
168+
Because it would be tedious for users to specify this requirement for tests,
169+
we intend to build debug builds with testability by default.
170+
171+
### Test Frameworks
172+
173+
Initially,
174+
the Swift Package Manager will use `XCTest` as its underlying test framework.
175+
176+
However, testing is an evolving artform,
177+
so we'd like to support other approaches
178+
that might allow frameworks other than XCTest
179+
to be supported by the package manager.
180+
We expect that such an implementation would take the form of
181+
a Swift protocol that the package manager defines,
182+
which other testing frameworks can adopt.
183+
184+
## Impact On Existing Code
185+
186+
Current releases of the package manager already exclude directories named
187+
"Tests" from target-determination. Directories named `FooTests` are not
188+
excluded, but as it stands this is a cause of compile failure, so in fact
189+
these changes will positively impact existing code.
190+
191+
## Alternatives Considered
192+
193+
Because this is a relatively broad proposal,
194+
no complete alternatives were considered.

0 commit comments

Comments
 (0)