使用RACSubject对RACSignal的简单用法进行单元测试

 kk1049057 发布于 2023-01-29 12:59

(我可能会以完全错误的方式使用它,所以请随意挑战这篇文章的前提.)

我有一个小的RACTest应用程序(听起来很熟悉吗?),我正在尝试进行单元测试.我想测试MPSTicker,它是最基于ReactiveCocoa的组件之一.如果累积标志设置为YES,它有一个每秒发送一次累积值的信号.我添加了一个初始化器来为其递增信号采用自定义信号,而不是仅基于定时器.

我想对MPSTicker的几个行为进行单元测试:

当累加使能且输入递增信号发送新值时,验证其累加信号是否正确递增(即单调增加).

当输入信号发送值时,验证它是否发送相同的值(而不是递增的值).

我添加了一个使用内置计时器来测试第一个增量的测试,并且它按照我的预期工作(尽管我正在寻求改进愚蠢的RACSequence初始化的建议,我做了以获得具有@(1)我想要的值的信号. )

我很难确定我可以向MPSTicker提供哪些输入信号,我可以手动发送值.我想象一个测试:






我尝试使用一个,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:调用从信号中获取第一个值,然后在我的主题上手动发送一个值,但该值未通过,并且测试在asynchronousFirstOrDefault:超时时失败.

我在这里错过了什么?

1 个回答
  • 这可能无法准确回答您的问题,但它可能会为您提供有关如何有效测试信号的见解.到目前为止,我自己使用了两种方法:

    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&Expecta

    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"
    

    2023-01-29 13:01 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有