如何在测试之间重置 Realm 的状态?

How can I reset Realm's state between tests?

我们一直在使用 RLMClearRealmCache 清除正在测试迁移的测试之间的 Realm 状态。如果缓存没有被清除,下一个测试将不会执行迁移,因为缓存仍然报告架构是最新的,即使我们已经删除并替换了领域固定文件(它有一个旧架构)。

RLMClearRealmCache 最近被移动到 Objective-C++ 文件,所以我们想停止使用它并避免在我们的项目中使用 Objective-C++。这仍然是 best/only 的做法吗?

明确地说,我们没有为这些规范使用内存中的 Realm。我们有一个 default.realm 从特定版本的设备保存的夹具文件,我们正在执行以下操作来使用它:

- (void)loadBundledRealmWithName:(NSString *)name;
{
    [self deleteOnDiskRealm];

    // copy over the file to the location
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *source = [[NSBundle bundleForClass:[self class]] pathForResource:name ofType:@"realm"];
    if (documentsDirectory && source) {
        NSString *destination = [documentsDirectory stringByAppendingPathComponent:kDefaultRealmFileName];
        [[NSFileManager defaultManager] copyItemAtPath:source toPath:destination error:nil];
    }
}

然而,在测试用例之间,没有调用 RLMClearRealmCache,似乎 Realm 的缓存确定迁移已经 运行,即使我们已经换掉了 [=15] =] 文件,他们需要再次 运行。

您可以为每个测试使用一个单独的内存中领域。当您这样做时,每个测试都会获得一个 "fresh" 领域,并且该领域的状态不会从一个测试泄漏到另一个测试。

要实现这一点,您只需将 Realm 的配置 inMemoryIdentifer 设置为 运行 之前的当前测试的名称。您可以在 XCTestCase 子类 setUp 方法中执行此操作(如 Realm 文档中所建议):

override func setUp() {
    super.setUp()
    Realm.Configuration.defaultConfiguration.inMemoryIdentifier = self.name
}

编辑:

这个答案不适合更新后的问题,但我还是会把它留在这里,因为它可能会帮助其他人寻找在测试之间重置 Realm 状态的方法。

我们最终让 Realm 清除了它的缓存,因为它会在不再被引用时清除缓存。追踪阻止它这样做的问题有点棘手:我们在测试运行之间保留对 Realm 对象的引用:

context(@"some context", ^{
    __block MyRealmObject *whoops;

    beforeEach(^{
        [specHelper loadBundledRealmWithName:@"release-50-fixture.realm"];
        [migrationManager performMigrations];
        whoops = [[MyRealmObject allObjects] firstObject];
    });

    it(@"first", ^{
        // migrations will run for this `it`
    });

    it(@"second", ^{
        // migrations will NOT run for this `it` since the old Realm is still around and its cache thinks migrations have already run (even though we've swapped out the backing DB).
        // the issue is that `whoops` is retaining a `MyRealmObject` and thus the Realm.
    });
});