Skip to content

Commit 58adcc1

Browse files
committed
Merge pull request #51 from mxcl/swiftpm-testing
Proposal for testing support in SwiftPM
2 parents c6764aa + 9aa76cc commit 58adcc1

File tree

1 file changed

+239
-0
lines changed

1 file changed

+239
-0
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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 arbitrary.
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+
A test-module is created per subdirectory of Tests, so:
56+
57+
Package
58+
├── Sources
59+
│ └── Foo
60+
│ └──Foo.swift
61+
└── Tests
62+
└── Foo
63+
└── Test.swift
64+
└── Bar
65+
└── Test.swift
66+
67+
Would create two test-modules. The modules in this example may
68+
test different aspects of the module Foo, it is entirely up
69+
to the package author.
70+
71+
Additionally we will support directories called `FooTests`.
72+
This layout style is prevalent in existing open source projects
73+
and supporting it will minimize vexation for their authors.
74+
However in the interest of consistency and the corresponding
75+
reduction of cognitive-load when examining new Swift packages
76+
we will not recommend this layout. For example:
77+
78+
Package
79+
└── Sources
80+
│ └── Foo.swift
81+
└── FooTests
82+
└── Test.swift
83+
84+
Additionally, we propose that building a module
85+
also builds that module's corresponding tests.
86+
Although this would result in slightly increased build times,
87+
we believe that tests are important enough to justify this
88+
(one might even consider slow building tests to be a code smell).
89+
We would prefer to go even further by executing the tests
90+
each time a module is built as well,
91+
but we understand that this would impede debug cycles.
92+
93+
As an exception, when packages are built in release mode we will
94+
not build tests because for release builds we should not enable
95+
testability. However, considering the need for release-mode testing
96+
this will be a future direction.
97+
98+
### Command-Line Interface
99+
100+
We propose the following syntax to execute tests:
101+
102+
$ swift build --test
103+
104+
Or:
105+
106+
$ swift build -t
107+
108+
In the future, we may choose to promote the `--test` option
109+
to be a subcommand of the `swift` command itself:
110+
111+
$ swift test
112+
113+
However, any such decision would warrant extensive design consideration,
114+
so as to avoid polluting or crowding the command-line interface.
115+
Should there be sufficient demand and justification for it, though,
116+
it would be straightforward to add this functionality.
117+
118+
### Command Output
119+
120+
Executing a test from the terminal will produce user-readable output.
121+
This should incorporate colorization and other formatting
122+
similar to other testing tools
123+
to indicate the success and failure of different tests.
124+
For example:
125+
126+
$ swift test --output module
127+
Running tests for PackageX (x/100)
128+
.........x.....x...................
129+
130+
Completed
131+
Elapsed time: 0.2s
132+
133+
98 Success
134+
2 Failure
135+
1 Warning
136+
137+
FAILURE: Tests/TestsA.swift:24 testFoo()
138+
XCTAssertTrue expected true, got false
139+
140+
FAILURE: Tests/TestsB.swift:10 testBar()
141+
XCTAssertEqual
142+
143+
WARNING: Tests/TestsC.swift:1
144+
"Some Warning"
145+
146+
An additional option may be passed to the testing command
147+
to output JUnit-style XML or other formats that can be integrated
148+
with continuous integration (CI) and other systems.
149+
150+
### Backwards Compatibility
151+
152+
In order to accomodate existing packages,
153+
we will allow test module targets and their targets
154+
to be overridden in the `Package.swift` manifest file.
155+
However, this functionality will likely not be implemented
156+
in the initial release of this feature,
157+
and instead be added at a later point in time.
158+
159+
### Automatic Dependency Determination
160+
161+
Testing is important and it is important to make the barrier to testing
162+
as minimal as possible. Thus, by analyzing the names of test targets,
163+
we will automatically determine the most likely dependency of that test
164+
and accomodate accordingly.
165+
For example,
166+
a test for "Foo" will depend on compilation of the library target `Foo`.
167+
Any additional dependencies or dependencies that could not be automatically determined
168+
would need to be specified in a package manifest separately.
169+
170+
### Debug / Release Configuration
171+
172+
Although tests built in debug configuration
173+
are generally run against modules also build in debug configuration,
174+
it is sometimes necessary to specify the build configuration for tests separately.
175+
It is also sometimes necessary to explicitly specify this information for every build,
176+
such as when building in a release configuration to execute performance tests.
177+
We would like to eventually support these use cases,
178+
however this will not be present in the initial implementation of this feature.
179+
180+
### Testability
181+
182+
Swift can build modules with "testability",
183+
which allows tests to access entities with `internal` access control.
184+
Because it would be tedious for users to specify this requirement for tests,
185+
we intend to build debug builds with testability by default.
186+
187+
### Test Frameworks
188+
189+
Initially,
190+
the Swift Package Manager will use `XCTest` as its underlying test framework.
191+
192+
However, testing is an evolving artform,
193+
so we'd like to support other approaches
194+
that might allow frameworks other than XCTest
195+
to be supported by the package manager.
196+
We expect that such an implementation would take the form of
197+
a Swift protocol that the package manager defines,
198+
which other testing frameworks can adopt.
199+
200+
201+
### Command Line Interface
202+
203+
The command line should accept the names of specific test cases to run:
204+
205+
swift build -t FooTestCase
206+
207+
Or specific tests:
208+
209+
swift build -t FooTestCase.test1
210+
211+
SwiftPM would forward arguments to the underlying testing framework and it
212+
would decide how to interpret them.
213+
214+
---
215+
216+
Sometimes test sources cannot compile and fixing them is no the most
217+
pressing priority. Thus it will be posssible to skip building tests
218+
with an additional flag:
219+
220+
swift build --without-tests
221+
222+
---
223+
224+
It is desirable to sometimes specify to only build specific tests, the
225+
command line for this will fall out of future work that allows specification
226+
of targets that `swift build` should speficially build in isolation.
227+
228+
229+
## Impact On Existing Code
230+
231+
Current releases of the package manager already exclude directories named
232+
"Tests" from target-determination. Directories named `FooTests` are not
233+
excluded, but as it stands this is a cause of compile failure, so in fact
234+
these changes will positively impact existing code.
235+
236+
## Alternatives Considered
237+
238+
Because this is a relatively broad proposal,
239+
no complete alternatives were considered.

0 commit comments

Comments
 (0)