Skip to content

Commit d0dbe91

Browse files
committed
Initial commit
0 parents  commit d0dbe91

File tree

99 files changed

+1772
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+1772
-0
lines changed

.github/workflows/swift.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# This workflow will build a Swift project
2+
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-swift
3+
4+
name: Swift
5+
6+
on:
7+
push:
8+
branches: [ "main" ]
9+
pull_request:
10+
branches: '**'
11+
12+
env:
13+
LCOV_PATH: .build/artifacts/info.lcov
14+
BUILD_FOLDER: .build/debug/ParameterizedTestingPackageTests.xctest/Contents/MacOS/ParameterizedTestingPackageTests
15+
PROFDATA_FOLDER: .build/debug/codecov/default.profdata
16+
17+
jobs:
18+
build:
19+
20+
runs-on: macos-12
21+
22+
steps:
23+
- uses: actions/checkout@v3
24+
25+
- name: Build
26+
run: swift build
27+
28+
- name: Run tests
29+
run: |
30+
swift test --enable-code-coverage
31+
xcrun llvm-cov report $BUILD_FOLDER -instr-profile $PROFDATA_FOLDER
32+
xcrun llvm-cov export -format="lcov" $BUILD_FOLDER -instr-profile $PROFDATA_FOLDER > $LCOV_PATH
33+
34+
- name: Determine coverage
35+
uses: codecov/[email protected]

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.build
2+
.swiftpm

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Cameron Cooke
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Package.resolved

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"pins" : [
3+
{
4+
"identity" : "swift-snapshot-testing",
5+
"kind" : "remoteSourceControl",
6+
"location" : "https://github.com/pointfreeco/swift-snapshot-testing.git",
7+
"state" : {
8+
"revision" : "f29e2014f6230cf7d5138fc899da51c7f513d467",
9+
"version" : "1.10.0"
10+
}
11+
}
12+
],
13+
"version" : 2
14+
}

Package.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// swift-tools-version: 5.7
2+
// The swift-tools-version declares the minimum version of Swift required to build this package.
3+
4+
import PackageDescription
5+
6+
let package = Package(
7+
name: "ParameterizedTesting",
8+
platforms: [
9+
.iOS(.v14),
10+
.macOS(.v10_15),
11+
],
12+
products: [
13+
.library(
14+
name: "ParameterizedTesting",
15+
targets: ["ParameterizedTesting"]
16+
),
17+
],
18+
dependencies: [
19+
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git", from: "1.10.0"),
20+
],
21+
targets: [
22+
.target(
23+
name: "ParameterizedTesting",
24+
dependencies: []
25+
),
26+
.testTarget(
27+
name: "ExampleTests",
28+
dependencies: [
29+
"ParameterizedTesting",
30+
.product(name: "SnapshotTesting", package: "swift-snapshot-testing"),
31+
],
32+
exclude: ["__Snapshots__"]
33+
)
34+
]
35+
)

README.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# ParameterizedTesting
2+
3+
![Run Tests](https://github.com/cameroncooke/SwiftParameterizedTesting/workflows/Swift/badge.svg)
4+
[![License](https://img.shields.io/badge/license-mit-brightgreen.svg)](https://en.wikipedia.org/wiki/MIT_License)
5+
[![codecov](https://codecov.io/gh/cameroncooke/SwiftParameterizedTesting/branch/main/graph/badge.svg?token=MPBFPN7OLI)](https://codecov.io/gh/cameroncooke/SwiftParameterizedTesting)
6+
7+
ParameterizedTesting is a Swift library for executing parameterized tests using XCTest for iOS.
8+
9+
## What are Parameterized tests?
10+
11+
A parameterized test is a test that runs over and over again using different values.
12+
13+
## Are there specific use-cases in mind?
14+
15+
Yes, this kind of test automation is especially helpful when snapshot testing where you want to ensure you have a snapshot representation for each configuration of a view where they are many permutations, but this can also be used for logic testing.
16+
17+
## Won't I just end up with a single test failing in Xcode if any of the permutations fail?
18+
19+
No, this is where the magic happens, `ParameterizedTesting` will dynamically create individual run-time tests for each permutation so that you know exactly which combination of values failed. When you run the test suite the each test will appear in the Xcode test navigator.
20+
21+
## Any warnings?
22+
23+
Yes, please use this library carefully! It's very easy to end up with 1000s of run-time tests with just a few lines of code. Please be aware that the size of the test suite will grow exponentially for each additional set of values.
24+
25+
```swift
26+
override class func values() -> ([WeatherData.Weather], [Int]) {
27+
(
28+
[.raining, .sunny, .cloudy, .snowing],
29+
[12, 34, 3, 22, 0]
30+
)
31+
}
32+
```
33+
34+
Above is a simple set of test values, two arrays of 4 and 5 values respectfully. This test alone will generate `4 * 5 = 20` tests.
35+
36+
Now let's look at a larger test dataset:
37+
38+
```swift
39+
override class func values() -> (
40+
[String],
41+
[Int],
42+
[String],
43+
[String],
44+
[Double],
45+
[String],
46+
[String],
47+
[String],
48+
[Bool]
49+
) {
50+
(
51+
[
52+
"raining",
53+
"sunny",
54+
"cloudy",
55+
"snowing",
56+
],
57+
[
58+
12,
59+
34,
60+
3,
61+
22,
62+
0,
63+
],
64+
[
65+
"apples",
66+
"oranges",
67+
],
68+
[
69+
"red",
70+
"blue",
71+
],
72+
[
73+
12.99,
74+
18.50,
75+
],
76+
[
77+
"GB",
78+
"EU",
79+
"FR",
80+
"US",
81+
],
82+
[
83+
"large",
84+
"small",
85+
],
86+
[
87+
"red",
88+
"blue",
89+
],
90+
[
91+
true,
92+
false,
93+
]
94+
)
95+
}
96+
```
97+
98+
Above is a larger set of test values, 9 arrays of 4, 5, 2, 2, 2, 4, 2, 2, 2 values respectfully. This test will generate `4 * 5 * 2 * 2 * 2 * 4 * 2 * 2 * 2 = 5120` tests!
99+
100+
It's important that you really consider the value of the parameterized tests and use wisely. Even though can test every combination doesn't mean you should and in general you shouldn't.
101+
102+
## Example usage
103+
104+
To use, in your test target create a new Swift file and subclass one of the `ParameterizedTestCase` base classes. Say you want to create test permutations from two sets of data you would use the `ParameterizedTestCase2` base class as shown in the below example, you can use up to 9 datasets in total. Just use corresponding class name i.e. `ParameterizedTestCase9`
105+
106+
```swift
107+
final class MySnapshotTests: ParameterizedTestCase2<Weather, CelsiusTemperature, Void> {
108+
override class var defaultTestSuite: XCTestSuite {
109+
customTestSuite(self)
110+
}
111+
112+
// MARK: - Internal -
113+
114+
override class func values() -> ([Weather], [Int]) {
115+
(
116+
[.raining, .sunny, .cloudy, .snowing],
117+
[12, 34, 3, 22, 0]
118+
)
119+
}
120+
121+
override func testAllCombinations(
122+
_ weather: Weather,
123+
_ temperature: CelsiusTemperature,
124+
_ expectedResult: Void?
125+
) {
126+
let view = WeatherView(
127+
viewModel: WeatherView.ViewModel(
128+
weather: weather,
129+
temperature: temperature,
130+
)
131+
)
132+
133+
assertSnapshot(
134+
matching: view,
135+
testName: "\(weather)_\(temperature)"
136+
)
137+
}
138+
}
139+
```
140+
141+
These classes use generics which you must define the types of when defining the class. In the above example the types of each dataset are defined as `<Weather, CelsiusTemperature, Void>`. The Void generic pamemter is a placeholder for an expected value which is only needed when creating logic tests. For snapshot tests it's not needed so here we seet this to void.
142+
143+
It's important that you override `defaultTestSuite` and paste in the following code:
144+
145+
```swift
146+
override class var defaultTestSuite: XCTestSuite {
147+
customTestSuite(self)
148+
}
149+
```
150+
151+
This is needed to workaround an issue when creating the run-time tests.
152+
153+
Next just override the `testAllCombinations()` method, this will be autocompleted for you if using Xcode with the parameters already correctly typed. In your method just add the test logic that performs whichever test action you want with the injected values.
154+
155+
156+
More fully worked examples including logic tests can be found in [Tests/ExampleTests](Tests/ExampleTests)
157+
158+
## Credits
159+
160+
This library is in part derived from https://github.com/approvals/ApprovalTests.Swift
161+
162+
## License
163+
164+
This library is released under the MIT license. See [LICENSE](LICENSE) for details.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// ParameterizedTestCaseKey.swift
3+
// Copyright © 2022 Cameron Cooke. All rights reserved.
4+
//
5+
6+
import Foundation
7+
8+
public enum ParameterizedTestCaseKey {
9+
static var value1 = "value1"
10+
static var value2 = "value2"
11+
static var value3 = "value3"
12+
static var value4 = "value4"
13+
static var value5 = "value5"
14+
static var value6 = "value6"
15+
static var value7 = "value7"
16+
static var value8 = "value8"
17+
static var value9 = "value9"
18+
static var expectedValue = "expectedValue"
19+
}

0 commit comments

Comments
 (0)