NGRValidation 1.3.3

NGRValidation 1.3.3

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2023年10月

Dmitry Lizin 维护。



  • Dmitry Lizin

Expecta

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。

手动设置

  1. 从 Github 上克隆 Expecta。
  2. 在你的项目目录中运行 rake 来构建框架和库。
  3. 如果你的 Xcode 项目中还没有,添加一个 Cocoa 或 Cocoa Touch 单元测试 Bundle 目标。
  4. 对于 OS X 项目,将 Expecta.frameworkProducts/osx 文件夹复制并添加到你的项目的测试目标中。

    对于 iOS 项目,将 Expecta.frameworkProducts/ios 文件夹复制并添加到你的项目的测试目标中。

    如果你更喜欢将 Expecta 作为静态库链接,也可以使用 libExpecta.a — iOS 7.x 及以下版本需要这样做。

  5. -ObjC-all_load 添加到你的 Xcode 项目的测试目标的 其他链接器标志 构建设置中。

  6. 现在,你可以在测试类中使用 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); 如果 xyz 的范围内,则通过。

expect(x).to.beCloseTo(y); 如果 x 接近 y,则通过。

expect(x).to.beCloseToWithin(y, z); 如果 xz 内接近 y,则通过。

expect(^{ /* code */ }).to.raise(@"ExceptionName"); 如果给定的代码块抛出名为 ExceptionName 的异常,则通过。

expect(^{ /* code */ }).to.raiseAny(); 如果给定的代码块抛出任何异常,则通过。

expect(x).to.conformTo(y); 如果 x 遵守协议 y,则通过。

expect(x).to.respondTo(y); 如果 xy 的选择器做出响应,则通过。

expect(^{ /* code */ }).to.notify(@"NotificationName"); 如果给定的代码块生成名为 NotificationName 的 NSNotification,则通过。

expect(^{ /* code */ }).to.notify(notification); 如果给定的代码块生成与传入的 notification 相等的 NSNotification,则通过。

expect(x).to.beginWith(y); 如果 NSString, NSArray 或 NSOrderedSet 的实例 xy 开头,则通过。还由 startWith 别名引用。

expect(x).to.endWith(y); 如果 NSString, NSArray 或 NSOrderedSet 的实例 xy 结尾,则通过。

expect(x).to.match(y); 如果 NSString 的实例 x 与正则表达式(以 NSString 提供的)y 匹配一次或多次,则通过。

匹配器反转

可以通过在前面添加 .notTo.toNot 来反转每个匹配器的标准。

expect(x).notTo.equal(y); 比较对象或原始数据 x 和 y,如果它们不等于,则通过。

异步测试

可以通过在前面添加 .will.willNotafter(...) 来使每个匹配器执行异步测试。

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许可协议授权。