OCHamcrest 是一个 Objective-C 模块,提供:
匹配器可以组合起来,在测试中创建灵活的意图表达。它们也可以用于其他目的,例如用户输入验证。
我们将从编写一个非常简单的 Xcode 单元测试开始,但我们将使用 OCHamcrest 的 assertThat 构造和一个预定义的匹配器,而不是使用 XCTest 的 XCTAssertEqualObjects 函数。
@import OCHamcrest;
@import XCTest;
@interface BiscuitTest : XCTestCase
@end
@implementation BiscuitTest
- (void)testEquals
{
Biscuit* theBiscuit = [[Biscuit alloc] initWithName:@"Ginger"];
Biscuit* myBiscuit = [[Biscuit alloc] initWithName:@"Ginger"];
assertThat(theBiscuit, equalTo(myBiscuit));
}
@end
assertThat 函数是一种程式化的句子,用于进行测试断言。 在此示例中,断言的主题是对象 theBiscuit,它是第一个方法参数。 第二个方法参数是 Biscuit 对象的匹配器,这里是一个检查一个对象是否等于另一个对象的匹配器,它使用 -isEqual: 方法。 由于 Biscuit 类定义了一个 -isEqual: 方法,因此测试通过。
实际上,OCHamcrest 的函数是用 "HC_" 包前缀声明的(例如 HC_assertThat 和 HC_equalTo),以避免名称冲突。 为了使测试编写更快且测试代码更易读,默认情况下提供了可选的短语法。 例如,不必编写 HC_assertThat,只需编写 assertThat。
OCHamcrest 附带了一个有用的匹配器库。
conformsTo - 匹配符合协议的对象equalTo - 匹配相等的对象hasDescription - 匹配对象的 -descriptionhasProperty - 匹配具有给定名称的方法的返回值instanceOf - 匹配对象类型isA - 精确匹配对象类型,不包括子类nilValue, notNilValue - 匹配 nil 或非 nilsameInstance - 匹配相同的对象throwsException - 匹配抛出异常的代码块closeTo - 匹配接近给定值的数字greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo - 匹配数字顺序isFalse - 匹配零isTrue - 匹配非零containsSubstring - 匹配字符串的一部分endsWith - 匹配字符串的结尾equalToIgnoringCase - 匹配完整的字符串,但忽略大小写equalToIgnoringWhitespace - 匹配完整的字符串,但忽略额外的空格startsWith - 匹配字符串的开头stringContainsInOrder, stringContainsInOrderIn - 匹配字符串的部分,按相对顺序排列allOf, allOfIn - 将所有匹配器“与”在一起anyOf, anyOfIn - 将所有匹配器“或”在一起anything - 匹配任何内容(在您不关心特定值的复合匹配器中很有用)isNot - 否定匹配器contains, containsIn - 完全匹配整个集合containsInAnyOrder, containsInAnyOrderIn - 匹配整个集合,但顺序不限containsInRelativeOrder, containsInRelativeOrderIn - 匹配包含按相对顺序排列的项目的集合everyItem - 如果集合中的每个项目都满足给定的匹配器,则匹配hasCount - 将元素的数量与另一个匹配器进行匹配hasCountOf - 匹配具有给定数量元素的集合hasEntries - 匹配具有字典中键值对的字典hasEntriesIn - 匹配具有列表中键值对的字典hasEntry - 匹配包含键值对的字典hasItem - 如果给定项目出现在集合中,则匹配hasItems, hasItemsIn - 如果所有给定项目都出现在集合中,则匹配,顺序不限hasKey - 匹配具有键的字典hasValue - 匹配具有值的字典isEmpty - 匹配空集合isIn - 当对象在给定集合中时匹配onlyContains, onlyContainsIn - 如果集合中的项目出现在给定的列表中,则匹配describedAs - 为匹配器提供自定义失败描述is - 用于提高可读性的装饰器 - 请参阅下面的“语法糖”许多这些匹配器的参数不仅接受匹配值,还接受另一个匹配器,因此可以组合匹配器以获得更大的灵活性。例如,only_contains(endsWith(@".")) 将匹配每个项目都是以句点结尾的字符串的任何集合。
OCHamcrest 努力使您的测试尽可能可读。例如,is 匹配器是一个包装器,它不会向底层匹配器添加任何额外的行为。以下断言都是等效的:
assertThat(theBiscuit, equalTo(myBiscuit));
assertThat(theBiscuit, is(equalTo(myBiscuit)));
assertThat(theBiscuit, is(myBiscuit));
允许最后一种形式,因为 is 使用 equalTo 包装非匹配器参数。其他将匹配器作为参数的匹配器提供了类似的快捷方式,用 equalTo 包装非匹配器参数。
assertWithTimeout 将持续评估表达式,直到满足匹配器或达到超时为止。例如:
assertWithTimeout(5, thatEventually(self.someString), is(@"expected"));
这会反复检查此字符串是否在 5 秒超时之前评估为“expected”。 thatEventually 是一个用于创建代码块的便捷宏。
OCHamcrest 捆绑了许多有用的匹配器,但您可能会发现您需要不时创建自己的匹配器来满足您的测试需求。有关更多信息,请参阅“编写自定义匹配器”指南。
Examples 文件夹显示了准备好通过 Swift Package Manager、CocoaPods 或通过预构建框架使用 OCHamcrest 的项目。
在 Package.swift 清单的 dependencies 数组中包含一个 OCHamcrest 包。
dependencies: [
.package(
url: "https://github.com/hamcrest/OCHamcrest",
.upToNextMajor(from: "9.1.0")
),
],
然后将 OCHamcrest 添加到您的 .testTarget 的依赖项中。
.testTarget(
name: "ExampleTests",
dependencies: [
"Example",
"OCHamcrest",
]
),
如果您想使用 Cocoapods 添加 OCHamcrest,请将以下依赖项添加到您的 Podfile。 大多数人希望他们的测试目标中使用 OCHamcrest,而不包含其主目标中的任何 pod。
target 'MyTests' do
inherit! :search_paths
use_frameworks!
pod 'OCHamcrest', '~> 9.1'
end
将以下内容添加到您的 Cartfile 中。
github "hamcrest/OCHamcrest" ~> 9.1
然后将构建的框架从相应的 Carthage/Build 目录拖到您的项目中,但禁用“将项目复制到目标组的文件夹”。
一个预构建的二进制文件可在 GitHub 上获得。 该二进制文件打包为 OCHamcrest.xcframework,包含以下架构:
将 XCFramework 拖到您的项目中。
如果您想自己构建 OCHamcrest,请克隆 repo,然后执行以下操作:
$ cd Resources
$ ./MakeDistribution.sh
Jon Reid 是iOS 单元测试示例的作者。 他的网站是 Quality Coding。