/
TestSuite.scala
218 lines (210 loc) · 9.58 KB
/
TestSuite.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
* Copyright 2001-2013 Artima, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.scalatest
import org.scalactic._
/**
* The base trait of ScalaTest's <em>synchronous testing styles</em>, which defines a
* <code>withFixture</code> lifecycle method that accepts as its parameter a test function
* that returns an <a href="Outcome.html"><code>Outcome</code></a>.
*
* <p>
* The <code>withFixture</code> method add by this trait has the
* following signature and implementation:
* </p>
*
* <pre class="stHighlighted">
* <span class="stReserved">def</span> withFixture(test: <span class="stType">NoArgTest</span>): <span class="stType">Outcome</span> = {
* test()
* }
* </pre>
*
* The <code>apply</code> method of test function interface,
* <code>NoArgTest</code>, also returns <code>Outcome</code>:
* </p>
*
* <pre class="stHighlighted">
* <span class="stLineComment">// In trait NoArgTest:</span>
* <span class="stReserved">def</span> apply(): <span class="stType">Outcome</span>
* </pre>
*
* <p>
* Because the result of a test is an <code>Outcome</code>, when the test function returns, the test body must have determined an outcome already. It
* will already be one of <a href="Succeeded$.html"><code>Succeeded</code></a>, <a href="Failed.html"><code>Failed</code></a>, <a href="Canceled.html"><code>Canceled</code></a>, or <a href="Pending$.html"></code>Pending</code></a>. This is
* also true when <code>withFixture(NoArgTest)</code> returns: because the result type of <code>withFixture(NoArgTest)</code> is <code>Outcome</code>,
* the test has by definition already finished execution.
* </p>
*
* <p>
* The recommended way to ensure cleanup is performed after a test body finishes execution is
* to use a <code>try</code>-<code>finally</code> clause.
* Using <code>try</code>-<code>finally</code> will ensure that cleanup will occur whether
* the test function completes abruptly by throwing a suite-aborting exception, or returns
* normally yielding an <code>Outcome</code>. Note that the only situation in which a test function
* will complete abruptly with an exception is if the test body throws a suite-aborting exception.
* Any other exception will be caught and reported as either a <code>Failed</code>, <code>Canceled</code>,
* or <code>Pending</code>.
* </p>
*
* <p>
* The <code>withFixture</code> method is designed to be stacked, and to enable this, you should always call the <code>super</code> implementation
* of <code>withFixture</code>, and let it invoke the test function rather than invoking the test function directly. In other words, instead of writing
* “<code>test()</code>”, you should write “<code>super.withFixture(test)</code>”. Thus, the recommended
* structure of a <code>withFixture</code> implementation that performs cleanup looks like this:
* </p>
*
* <pre class="stHighlighted">
* <span class="stLineComment">// Your implementation</span>
* <span class="stReserved">override</span> <span class="stReserved">def</span> withFixture(test: <span class="stType">NoArgTest</span>) = {
* <span class="stLineComment">// Perform setup here</span>
* <span class="stReserved">try</span> {
* <span class="stReserved">super</span>.withFixture(test) <span class="stLineComment">// Invoke the test function</span>
* } <span class="stReserved">finally</span> {
* <span class="stLineComment">// Perform cleanup here</span>
* }
* }
* </pre>
*
* <p>
* If you have no cleanup to perform, you can write <code>withFixture</code> like this instead:
* </p>
*
* <pre class="stHighlighted">
* <span class="stLineComment">// Your implementation</span>
* <span class="stReserved">override</span> <span class="stReserved">def</span> withFixture(test: <span class="stType">NoArgTest</span>) = {
* <span class="stLineComment">// Perform setup here</span>
* <span class="stReserved">super</span>.withFixture(test) <span class="stLineComment">// Invoke the test function</span>
* }
* </pre>
*
* <p>
* If you want to perform an action only for certain outcomes, you can use
* a pattern match.
* For example, if you want to perform an action if a test fails, you'd
* match on <code>Failed</code>, like this:
* </p>
*
* <pre class="stHighlighted">
* <span class="stLineComment">// Your implementation</span>
* <span class="stReserved">override</span> <span class="stReserved">def</span> withFixture(test: <span class="stType">NoArgTest</span>) = {
* <br/> <span class="stLineComment">// Perform setup here</span>
* <br/> <span class="stReserved">val</span> outcome = <span class="stReserved">super</span>.withFixture(test) <span class="stLineComment">// Invoke the test function</span>
* <br/> outcome <span class="stReserved">match</span> {
* <span class="stReserved">case</span> failed: <span class="stType">Failed</span> =>
* <span class="stLineComment">// perform action that you want to occur</span>
* <span class="stLineComment">// only if a test fails here</span>
* failed
* <span class="stReserved">case</span> other => other
* }
* }
* </pre>
*
* <p>
* If you want to change the outcome in some way in <code>withFixture</code>, you can also
* use a pattern match.
* For example, if a particular exception intermittently causes a test to fail, and can
* transform those failures into cancelations, like this:
* </p>
*
* <pre class="stHighlighted">
* <span class="stLineComment">// Your implementation</span>
* <span class="stReserved">override</span> <span class="stReserved">def</span> withFixture(test: <span class="stType">NoArgTest</span>) = {
* <br/> <span class="stReserved">super</span>.withFixture(test) <span class="stReserved">match</span> {
* <span class="stReserved">case</span> <span class="stType">Failed</span>(ex: <span class="stType">ParticularException</span>) =>
* <span class="stType">Canceled</span>(<span class="stQuotedString">"Muting flicker"</span>, ex)
* <span class="stReserved">case</span> other => other
* }
* }
* </pre>
*/
trait TestSuite extends Suite { thisTestSuite =>
/**
* A test function taking no arguments and returning an <code>Outcome</code>.
*
* <p>
* For more detail and examples, see the relevant section in the
* <a href="FlatSpec.html#withFixtureNoArgTest">documentation for trait <code>fixture.FlatSpec</code></a>.
* </p>
*/
protected trait NoArgTest extends (() => Outcome) with TestData {
/**
* Runs the body of the test, returning an <code>Outcome</code>.
*/
def apply(): Outcome
}
// Keep this out of the public until there's a use case demonstrating its need
private[scalatest] object NoArgTest {
def apply(test: NoArgTest)(f: => Outcome): NoArgTest = {
new NoArgTest {
def apply(): Outcome = { f }
val text: String = test.text
val configMap: ConfigMap = test.configMap
val scopes: collection.immutable.IndexedSeq[String] = test.scopes
val name: String = test.name
val tags: Set[String] = test.tags
val pos: Option[source.Position] = test.pos
}
}
}
/**
* Run the passed test function in the context of a fixture established by this method.
*
* <p>
* This method should set up the fixture needed by the tests of the
* current suite, invoke the test function, and if needed, perform any clean
* up needed after the test completes. Because the <code>NoArgTest</code> function
* passed to this method takes no parameters, preparing the fixture will require
* side effects, such as reassigning instance <code>var</code>s in this <code>Suite</code> or initializing
* a globally accessible external database. If you want to avoid reassigning instance <code>var</code>s
* you can use <a href="FixtureSuite.html">FixtureSuite</a>.
* </p>
*
* <p>
* This trait's implementation of <code>runTest</code> invokes this method for each test, passing
* in a <code>NoArgTest</code> whose <code>apply</code> method will execute the code of the test.
* </p>
*
* <p>
* This trait's implementation of this method simply invokes the passed <code>NoArgTest</code> function.
* </p>
*
* @param test the no-arg test function to run with a fixture
*/
protected def withFixture(test: NoArgTest): Outcome = {
test()
}
/**
* Run an async test.
*
* <p>
* This method is redefine in this trait solely to narrow its contract. Subclasses must implement
* this method to call the <code>withFixture(NoArgTest)</code> method, which is defined in this trait.
* </p>
*
* <p>
* This trait's implementation of this method simply returns <code>SucceededStatus</code>
* and has no other effect.
* </p>
*
* @param testName the name of one async test to execute.
* @param args the <code>Args</code> for this run
* @return a <code>Status</code> object that indicates when the test started by this method
* has completed, and whether or not it failed.
*
* @throws NullArgumentException if either <code>testName</code> or <code>args</code>
* is <code>null</code>.
*/
protected override def runTest(testName: String, args: Args): Status = SucceededStatus
}