Objective-C 和 Cocoa 的匹配器框架。
使用 Expecta 比其他匹配器框架的主要优势是你不需要指定数据类型。此外,Expecta 匹配器的语法更易于阅读,并且不受括号的困扰。
expect(@"foo").to.equal(@"foo"); // `to` is a syntactic sugar and can be safely omitted.
expect(foo).notTo.equal(1);
expect([bar isBar]).to.equal(YES);
expect(baz).to.equal(3.14159);
Expecta 适用于所有框架:它与 XCTest 和兼容 XCTest 的测试框架(如 Specta)配合良好。
您可以使用 Carthage、CocoaPods 或 完全手动 来设置 Expecta。
rake
来构建框架和库。对于 OS X 项目,将 Expecta.framework
从 Products/osx
文件夹复制并添加到你的项目的测试目标中。
对于 iOS 项目,将 Expecta.framework
从 Products/ios
文件夹复制并添加到你的项目的测试目标中。
如果你更喜欢将 Expecta 作为静态库链接,也可以使用 libExpecta.a
— iOS 7.x 及以下版本需要这样做。
将 -ObjC
和 -all_load
添加到你的 Xcode 项目的测试目标的 其他链接器标志 构建设置中。
现在,你可以在测试类中使用 Expecta,通过添加以下导入
@import Expecta; // If you're using Expecta.framework
// OR
#import <Expecta/Expecta.h> // If you're using the static library, or the framework
expect(x).to.equal(y);
比较 x 和 y 对象或基本数据,如果它们相同(==)或等效(isEqual:),则通过。
expect(x).to.beIdenticalTo(y);
比较 x 和 y 对象,如果它们相同并且具有相同的内存地址,则通过。
expect(x).to.beNil();
如果 x 是 nil,则通过。
expect(x).to.beTruthy();
如果 x 进行求值得到真(非零),则通过。
expect(x).to.beFalsy();
如果 x 进行求值得到假(零),则通过。
expect(x).to.contain(y);
如果 NSArray 或 NSString 实例 x 包含 y,则通过。
expect(x).to.beSupersetOf(y);
如果 NSArray, NSSet, NSDictionary 或 NSOrderedSet 的实例 x 包含 y 的所有元素,则通过。
expect(x).to.haveCountOf(y);
如果 NSArray, NSSet, NSDictionary 或 NSString 的实例 x 的计数或长度为 y,则通过。
expect(x).to.beEmpty();
如果 NSArray, NSSet, NSDictionary 或 NSString 的实例 x 的计数或长度为空,则通过。
expect(x).to.beInstanceOf([Foo class]);
如果 x 是类 Foo 的实例,则通过。
expect(x).to.beKindOf([Foo class]);
如果 x 是类 Foo 的实例,或者 x 是继承自类 Foo 的任何类的实例,则通过。
expect([Foo class]).to.beSubclassOf([Bar class]);
如果类 Foo 是类 Bar 的子类,或者与类 Bar 相同,则通过。对类簇使用 beKindOf()。
expect(x).to.beLessThan(y);
如果x
小于y
,则通过。
expect(x).to.beLessThanOrEqualTo(y);
如果x
小于或等于y
,则通过。
expect(x).to.beGreaterThan(y);
如果x
大于y
,则通过。
expect(x).to.beGreaterThanOrEqualTo(y);
如果x
大于或等于y
,则通过。
expect(x).to.beInTheRangeOf(y,z);
如果x
在y
和z
的范围内,则通过。
expect(x).to.beCloseTo(y);
如果x
接近y
,则通过。
expect(x).to.beCloseToWithin(y, z);
如果x
在z
内接近y
,则通过。
expect(^{ /* code */ }).to.raise(@"ExceptionName");
如果给定的代码块抛出名为ExceptionName
的异常,则通过。
expect(^{ /* code */ }).to.raiseAny();
如果给定的代码块抛出任何异常,则通过。
expect(x).to.conformTo(y);
如果x
遵守协议y
,则通过。
expect(x).to.respondTo(y);
如果x
对y
的选择器做出响应,则通过。
expect(^{ /* code */ }).to.notify(@"NotificationName");
如果给定的代码块生成名为NotificationName
的 NSNotification,则通过。
expect(^{ /* code */ }).to.notify(notification);
如果给定的代码块生成与传入的notification
相等的 NSNotification,则通过。
expect(x).to.beginWith(y);
如果 NSString, NSArray 或 NSOrderedSet 的实例x
以y
开头,则通过。还由startWith
别名引用。
expect(x).to.endWith(y);
如果 NSString, NSArray 或 NSOrderedSet 的实例x
以y
结尾,则通过。
expect(x).to.match(y);
如果 NSString 的实例x
与正则表达式(以 NSString 提供的)y
匹配一次或多次,则通过。
可以通过在前面添加 .notTo
或 .toNot
来反转每个匹配器的标准。
expect(x).notTo.equal(y);
比较对象或原始数据 x 和 y,如果它们不等于,则通过。
可以通过在前面添加 .will
、.willNot
或 after(...)
来使每个匹配器执行异步测试。
expect(x).will.beNil();
如果 x 在默认超时之前变为 nil,则通过。
expect(x).willNot.beNil();
如果 x 在默认超时之前变为非 nil,则通过。
expect(x).after(3).to.beNil();
如果 x 在 3.0 秒后变为 nil,则通过。
expect(x).after(2.5).notTo.equal(42);
如果 x 在 2.5 秒后不等于 42,则通过。
默认超时为 1.0 秒,如果未指定其他情况,则用于所有匹配器。可以通过调用 [Expecta setAsynchronousTestTimeout:x]
来更改此设置,其中 x
是以秒为单位的所需超时。
describe(@"Foo", ^{
beforeAll(^{
// All asynchronous matching using `will` and `willNot`
// will have a timeout of 2.0 seconds
[Expecta setAsynchronousTestTimeout:2];
});
it(@"will not be nil", ^{
// Test case where default timeout is used
expect(foo).willNot.beNil();
});
it(@"should equal 42 after 3 seconds", ^{
// Signle case where timeout differs from the default
expect(foo).after(3).to.equal(42);
});
});
您可以通过使用failure
属性来使测试失败。这可以用来测试分支。
failure(@"这不是应该发生的");
会直接使测试失败。
使用Expecta提供的特殊宏编写一个新的匹配器非常简单。看看.beKindOf()
匹配器是如何定义的
EXPMatchers+beKindOf.h
#import "Expecta.h"
EXPMatcherInterface(beKindOf, (Class expected));
// 1st argument is the name of the matcher function
// 2nd argument is the list of arguments that may be passed in the function
// call.
// Multiple arguments are fine. (e.g. (int foo, float bar))
#define beAKindOf beKindOf
EXPMatchers+beKindOf.m
#import "EXPMatchers+beKindOf.h"
EXPMatcherImplementationBegin(beKindOf, (Class expected)) {
BOOL actualIsNil = (actual == nil);
BOOL expectedIsNil = (expected == nil);
prerequisite(^BOOL {
return !(actualIsNil || expectedIsNil);
// Return `NO` if matcher should fail whether or not the result is inverted
// using `.Not`.
});
match(^BOOL {
return [actual isKindOfClass:expected];
// Return `YES` if the matcher should pass, `NO` if it should not.
// The actual value/object is passed as `actual`.
// Please note that primitive values will be wrapped in NSNumber/NSValue.
});
failureMessageForTo(^NSString * {
if (actualIsNil)
return @"the actual value is nil/null";
if (expectedIsNil)
return @"the expected value is nil/null";
return [NSString
stringWithFormat:@"expected: a kind of %@, "
"got: an instance of %@, which is not a kind of %@",
[expected class], [actual class], [expected class]];
// Return the message to be displayed when the match function returns `YES`.
});
failureMessageForNotTo(^NSString * {
if (actualIsNil)
return @"the actual value is nil/null";
if (expectedIsNil)
return @"the expected value is nil/null";
return [NSString
stringWithFormat:@"expected: not a kind of %@, "
"got: an instance of %@, which is a kind of %@",
[expected class], [actual class], [expected class]];
// Return the message to be displayed when the match function returns `NO`.
});
}
EXPMatcherImplementationEnd
通过简单地定义匹配器接口,匹配器实现将在运行时通过委托到您对象上的谓词方法来处理,可以添加谓词匹配器。
例如,如果您有以下类
@interface LightSwitch : NSObject
@property (nonatomic, assign, getter=isTurnedOn) BOOL turnedOn;
@end
@implementation LightSwitch
@synthesize turnedOn;
@end
编写一个断言来检查开关闭是否打开的标准方式是
expect([lightSwitch isTurnedOn]).to.beTruthy();
然而,如果我们定义一个自定义谓词匹配器
EXPMatcherInterface(isTurnedOn, (void));
(注意:我们还没有定义匹配器的实现,只是定义了其接口)
现在您可以按照以下方式编写您的断言
expect(lightSwitch).isTurnedOn();
_
)作为实例变量的前缀。EXP
作为在全局作用域中定义的自定义类和函数的前缀。版权所有(c)2012-2015 Specta Team。本软件依照MIT许可协议授权。