【问题标题】:Unit-testing a simple usage of RACSignal with RACSubject使用 RACSubject 对 RACSignal 的简单用法进行单元测试
【发布时间】:2014-02-04 23:28:58
【问题描述】:

(我可能以完全不正确的方式使用它,所以请随意挑战这篇文章的前提。)

我有一个小的RACTest app (sound familiar?) 我正在尝试对其进行单元测试。我想测试MPSTicker,它是最基于 ReactiveCocoa 的组件之一。如果累积标志设置为“是”,它有一个每秒发送一次累积值的信号。我added an initializer 为其递增信号采用自定义信号,而不是仅基于计时器。

我想对 MPSTicker 的一些行为进行单元测试:

  • 当启用累加并且输入递增信号发送新值时,验证其累加信号是否正确递增(即单调递增)。
  • 验证它在输入信号发送值时发送相同的值(而不是增加的值)。

我添加了a test that uses the built-in timer to test the first increment,它按我的预期工作(尽管我正在寻求关于改进愚蠢的 RACSequence 初始化的建议,以便获得我想要的 @(1) 值的信号。)

我很难弄清楚我可以向 MPSTicker 提供哪些输入信号,而我可以手动向其发送值。我正在设想一个类似的测试:

<set up ticker>
<send a tick value>
<verify accumulated value is 1>
<send another value>
<verify accumulated value is 2>

我尝试使用RACSubject,所以我可以使用sendNext: 来推送我认为合适的值,但它并没有像我预期的那样工作。这是两个损坏的测试:

- (void)testManualTimerTheFirst
{
    // Create a custom tick with one value to send.
    RACSubject *controlledSignal = [RACSubject subject];
    MPSTicker *ticker = [[MPSTicker alloc] initWithTickSource:controlledSignal];
    [ticker.accumulateSignal subscribeNext:^(id x) {
        NSLog(@"%s value is %@", __func__, x);
    }];

    [controlledSignal sendNext:@(2)];
}

- (void)testManualTimerTheSecond
{
    // Create a custom tick with one value to send.
    RACSubject *controlledSignal = [RACSubject subject];
    MPSTicker *ticker = [[MPSTicker alloc] initWithTickSource:controlledSignal];

    BOOL success = NO;
    NSError *error = nil;
    id value = [ticker.accumulateSignal asynchronousFirstOrDefault:nil success:&success error:&error];

    if (!success) {
        XCTAssertTrue(success, @"Signal failed to return a value. Error: %@", error);
    } else {
        XCTAssertNotNil(value, @"Signal returned a nil value.");
        XCTAssertEqualObjects(@(1), value, @"Signal returned an unexpected value.");
    }

    // Send a value.
    [controlledSignal sendNext:@(1)];
}

testManualTimerTheFirst 中,我从未看到controlledSignalsendNext: 中的任何值通过我的subscribeNext: 块。

testManualTimerTheSecond 中,我尝试使用asynchronousFirstOrDefault: 调用从信号中获取第一个值,然后在我的主题上手动发送一个值,但该值没有通过,当@987654337 时测试失败@超时。

我在这里错过了什么?

【问题讨论】:

    标签: unit-testing reactive-cocoa


    【解决方案1】:

    这可能无法准确回答您的问题,但它可以让您深入了解如何有效地测试您的信号。到目前为止,我自己使用了 2 种方法:

    XCTestCase 和 TRVSMonitor

    TRVSMonitor 是一个小型实用程序,它会在您运行断言时为您暂停当前线程。例如:

    TRVSMonitor *monitor = [TRVSMonitor monitor];
    
    [[[self.service searchPodcastsWithTerm:@"security now"] collect] subscribeNext:^(NSArray *results) {
        XCTAssertTrue([results count] > 0, @"Results count should be > 0";
        [monitor signal];
    
    } error:^(NSError *error) {
        XCTFail(@"%@", error);
        [monitor signal];
    }];
    
    [monitor wait];
    

    如您所见,我告诉监视器在我订阅后立即等待,并在 subscribeNext 结束时发出停止等待的信号,并发出错误块以使其继续执行(因此其他测试也可以运行)。这种方法的好处是不依赖于静态超时,因此您的代码可以根据需要运行。

    使用 CocoaPods,您可以轻松地将 TRVSMonitor 添加到您的项目中:

    pod "TRVSMonitor", "~> 0.0.3"
    

    前景与预期

    Specta 是一个 BDD/TDD(行为驱动/测试驱动)测试框架。 Expecta 是一个提供更方便的断言匹配器的框架。它内置了对异步测试的支持。它使您能够使用 ReactiveCocoa 编写更具描述性的测试,如下所示:

    it(@"should return a valid image, with cache state 'new'", ^AsyncBlock {
        [[cache imageForURL:[NSURL URLWithString:SECURITY_NOW_ARTWORK_URL]] subscribeNext:^(UIImage *image) {
            expect(image).notTo.beNil();
            expect(image.cacheState).to.equal(JPImageCacheStateNew);
    
        } error:^(NSError *error) {
            XCTFail(@"%@", error);
    
        } completed:^{
            done();
        }];
    });
    

    注意 ^AsyncBlock { 的使用。简单地使用 ^ { 将意味着同步测试。

    在这里调用 done() 函数来表示异步测试的结束。我相信 Specta 在内部使用 10 秒超时。

    使用 CocoaPods,您可以轻松添加 Expecta 和 Specta:

    pod "Expecta", "~> 0.2.3"
    pod "Specta", "~> 0.2.1"
    

    【讨论】:

      【解决方案2】:

      看到这个问题:https://stackoverflow.com/a/19127547/420594

      XCAsyncTestCase 有一些额外的功能允许异步测试用例。

      另外,我还没有深入研究它,但您对ReactiveCocoaTests 有兴趣吗?乍一看,他们似乎在使用 Expecta。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-08
        相关资源
        最近更新 更多