Skip to content

Commit 8af87e2

Browse files
authored
Merge pull request #283 from drodriguez/add-teardown-block
Implement XCTestCase.addTeardownBlock
2 parents 0541fa8 + 11368cd commit 8af87e2

File tree

3 files changed

+120
-3
lines changed

3 files changed

+120
-3
lines changed

Sources/XCTest/Public/XCTestCase.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ open class XCTestCase: XCTest {
132132
expected: false)
133133
}
134134
}
135+
runTeardownBlocks()
135136
tearDown()
136137
}
137138

@@ -178,6 +179,32 @@ open class XCTestCase: XCTest {
178179
/// class.
179180
open class func tearDown() {}
180181

182+
private var teardownBlocks: [() -> Void] = []
183+
private var teardownBlocksDequeued: Bool = false
184+
private let teardownBlocksQueue: DispatchQueue = DispatchQueue(label: "org.swift.XCTest.XCTestCase.teardownBlocks")
185+
186+
/// Registers a block of teardown code to be run after the current test
187+
/// method ends.
188+
open func addTeardownBlock(_ block: @escaping () -> Void) {
189+
teardownBlocksQueue.sync {
190+
precondition(!self.teardownBlocksDequeued, "API violation -- attempting to add a teardown block after teardown blocks have been dequeued")
191+
self.teardownBlocks.append(block)
192+
}
193+
}
194+
195+
private func runTeardownBlocks() {
196+
let blocks = teardownBlocksQueue.sync { () -> [() -> Void] in
197+
self.teardownBlocksDequeued = true
198+
let blocks = self.teardownBlocks
199+
self.teardownBlocks = []
200+
return blocks
201+
}
202+
203+
for block in blocks.reversed() {
204+
block()
205+
}
206+
}
207+
181208
open var continueAfterFailure: Bool {
182209
get {
183210
return true
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// RUN: %{swiftc} %s -g -o %T/TestCaseLifecycleMisuse
2+
// RUN: %T/TestCaseLifecycleMisuse > %t || true
3+
// RUN: %{xctest_checker} %t %s
4+
5+
#if os(macOS)
6+
import SwiftXCTest
7+
#else
8+
import XCTest
9+
#endif
10+
11+
// CHECK: Test Suite 'All tests' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
12+
// CHECK: Test Suite '.*\.xctest' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
13+
14+
// CHECK: Test Suite 'TeardownBlocksMisuseTestCase' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
15+
class TeardownBlocksMisuseTestCase: XCTestCase {
16+
17+
// CHECK: Test Case 'TeardownBlocksMisuseTestCase.test_addingATeardownBlockLate_crashes' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
18+
func test_addingATeardownBlockLate_crashes() {
19+
addTeardownBlock { [weak self] in
20+
guard let self = self else {
21+
XCTFail("self should still exist at this point")
22+
return
23+
}
24+
// The following line should crash and nothing more will be printed
25+
self.addTeardownBlock {
26+
print("This should not be printed")
27+
}
28+
}
29+
}
30+
31+
static var allTests = {
32+
return [
33+
("test_addingATeardownBlockLate_crashes", test_addingATeardownBlockLate_crashes),
34+
]
35+
}()
36+
}
37+
38+
XCTMain([
39+
testCase(TeardownBlocksMisuseTestCase.allTests),
40+
])

Tests/Functional/TestCaseLifecycle/main.swift

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,12 +86,62 @@ class NewInstanceForEachTestTestCase: XCTestCase {
8686
// CHECK: \t Executed 2 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
8787

8888

89+
// CHECK: Test Suite 'TeardownBlocksTestCase' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
90+
class TeardownBlocksTestCase: XCTestCase {
91+
static var allTests = {
92+
return [
93+
("test_withoutTeardownBlocks", test_withoutTeardownBlocks),
94+
("test_withATeardownBlock", test_withATeardownBlock),
95+
("test_withSeveralTeardownBlocks", test_withSeveralTeardownBlocks),
96+
]
97+
}()
98+
99+
override func tearDown() {
100+
print("In tearDown function")
101+
}
102+
103+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withoutTeardownBlocks' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
104+
// CHECK: In tearDown function
105+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withoutTeardownBlocks' passed \(\d+\.\d+ seconds\)
106+
func test_withoutTeardownBlocks() {
107+
// Intentionally blank
108+
}
109+
110+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withATeardownBlock' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
111+
// CHECK: In teardown block A
112+
// CHECK: In tearDown function
113+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withATeardownBlock' passed \(\d+\.\d+ seconds\)
114+
func test_withATeardownBlock() {
115+
addTeardownBlock {
116+
print("In teardown block A")
117+
}
118+
}
119+
120+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withSeveralTeardownBlocks' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
121+
// CHECK: In teardown block C
122+
// CHECK: In teardown block B
123+
// CHECK: In tearDown function
124+
// CHECK: Test Case 'TeardownBlocksTestCase.test_withSeveralTeardownBlocks' passed \(\d+\.\d+ seconds\)
125+
func test_withSeveralTeardownBlocks() {
126+
addTeardownBlock {
127+
print("In teardown block B")
128+
}
129+
addTeardownBlock {
130+
print("In teardown block C")
131+
}
132+
}
133+
}
134+
// CHECK: Test Suite 'TeardownBlocksTestCase' passed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
135+
// CHECK: \t Executed 3 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
136+
137+
89138
XCTMain([
90139
testCase(SetUpTearDownTestCase.allTests),
91-
testCase(NewInstanceForEachTestTestCase.allTests)
140+
testCase(NewInstanceForEachTestTestCase.allTests),
141+
testCase(TeardownBlocksTestCase.allTests),
92142
])
93143

94144
// CHECK: Test Suite '.*\.xctest' passed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
95-
// CHECK: \t Executed 3 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
145+
// CHECK: \t Executed 6 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
96146
// CHECK: Test Suite 'All tests' passed at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
97-
// CHECK: \t Executed 3 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds
147+
// CHECK: \t Executed 6 tests, with 0 failures \(0 unexpected\) in \d+\.\d+ \(\d+\.\d+\) seconds

0 commit comments

Comments
 (0)