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
- 匹配对象的 -description
hasProperty
- 匹配具有给定名称的方法的返回值instanceOf
- 匹配对象类型isA
- 精确匹配对象类型,不包括子类nilValue
, notNilValue
- 匹配 nil
或非 nil
sameInstance
- 匹配相同的对象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。