Using TestCleaner, we can clean this up a little without sacrificing Xcode’s ability to highlight lines containing failing tests. We also recommend using a local typealias to help reduce line noise:
Now, the assert operation (“equal”) needs to be written in just one place, making the block of tests less error-prone and the intent clearer. It also reduces line length, although the typealias is helping there.
Focus or Skip Tests
Borrowing syntax from Quick, you can focus any tests by adding an f to the beginning, and only those tests will execute on the next run, allowing you to debug individual cases without having to haphazardly comment and uncomment lines:
func testExpressibleByStringLiteral() {
typealias V = Version
assertEqual(testCases: [
Pair("1", V(major: 1)),
fPair("1.0", V(major: 1)), // Only this test will run.
Pair("1.0.0", V(major: 1)),
]
}
You can also skip test cases by prepending them with x:
func testExpressibleByStringLiteral() {
typealias V = Version
assertEqual(testCases: [
Pair("1", V(major: 1)),
xPair("1.0", V(major: 1)), // These last two tests will be ignored.
xPair("1.0.0", V(major: 1)),
]
}
These can be combined in a single test for added flexibility: use xPair to skip some tests to start with, then focus in on just one to debug it with fPair.
All Available Comparators
TestCleaner mirrors the full range of XCTAssert functions available:
Boolean (true/false)
LessThan <
GreaterThan >
LessThanOrEqual <=
GreaterThanOrEqual >=
Equal ==
Equal (with floating-point accuracy) ==
NotEqual !=
NotEqual (with floating-point accuracy) !=
Custom Assertions
If you have a custom assertion function, you can use the assertCustom function to use it with TestCleaner. Just make sure your custom assertion takes file: StaticString, line: UInt parameters, and forward the ones that the tests closure in assertCustom passes to you.
assertCustom(
testCases: [
Pair(someLeftValue, someRightValue),
Pair(anotherLeftValue, anotherRightValue),
],
tests: { pair, file, line in
myCustomAssertion(
try pair.left, try pair.right,
message: pair.message,
file: file, line: line // <-- ⚠️ this is important!
)
try youCanAlsoThrowErrorsInHere() // They will also get attributed to the correct line.
}
)
When To Use TestCleaner
This tool is ideal for tests of pure transformations, where a certain input will always produce the same output. Examples include: parsing, mapping, converting, and calculating. It is not intended to be used for integration-style tests, where each assertion is preceded by many lines of setup.
Further Reading
TestCleaner was inspired by a blog post which was in turn inspired by a conversation with Brian King.
TestCleaner
Tidy up repetitive XCTests by removing boilerplate so you can focus on each test’s inputs and outputs.
Here is an existing XCTest that confirms that a
Version
type’sExpressibleByStringLiteral
is working by comparing the results to known good values:Using TestCleaner, we can clean this up a little without sacrificing Xcode’s ability to highlight lines containing failing tests. We also recommend using a local
typealias
to help reduce line noise:Now, the assert operation (“equal”) needs to be written in just one place, making the block of tests less error-prone and the intent clearer. It also reduces line length, although the
typealias
is helping there.Focus or Skip Tests
Borrowing syntax from Quick, you can focus any tests by adding an
f
to the beginning, and only those tests will execute on the next run, allowing you to debug individual cases without having to haphazardly comment and uncomment lines:You can also skip test cases by prepending them with
x
:These can be combined in a single test for added flexibility: use
xPair
to skip some tests to start with, then focus in on just one to debug it withfPair
.All Available Comparators
TestCleaner mirrors the full range of XCTAssert functions available:
<
>
<=
>=
==
==
!=
!=
Custom Assertions
If you have a custom assertion function, you can use the
assertCustom
function to use it with TestCleaner. Just make sure your custom assertion takesfile: StaticString, line: UInt
parameters, and forward the ones that thetests
closure inassertCustom
passes to you.When To Use TestCleaner
This tool is ideal for tests of pure transformations, where a certain input will always produce the same output. Examples include: parsing, mapping, converting, and calculating. It is not intended to be used for integration-style tests, where each assertion is preceded by many lines of setup.
Further Reading
TestCleaner was inspired by a blog post which was in turn inspired by a conversation with Brian King.
The spray bottle image was made using Blender, and the project file is hosted at ZevEisenberg/TestCleanerIcon.