1

虽然我在 SO 中看到过类似的问题,但似乎没有一个答案能解决我的问题。

我有一个由 mogenerator 生成的具有自定义功能的 NSManagedObject 类(不在模型中):

@interface MyManagedClass : _MyManagedClass {
-(NSNumber*)getRandomNumber2;
-(void)function_I_want_to_test;
}

我的 function_I_want_to_test() 取决于 random() 的结果,这是我在测试期间必须控制的。因为我不能模拟 random() 我构建了一个函数包装器,顺便说一下,它不是静态的,因为我在 OCMock 和静态类函数方面遇到了很多问题。

我的单元测试的设置如下:

[MagicalRecord setDefaultModelFromClass:[self class]];
[MagicalRecord setupCoreDataStackWithInMemoryStore];

使用调试器,我可以验证模型是否已正确加载。另外,如果我以非神奇的方式进行操作:

    NSBundle *b = [NSBundle bundleForClass:[self class]];
    model = [NSManagedObjectModel mergedModelFromBundles:@[b]];

在此之后,我无法创建任何模拟来存根我的 random() 包装函数

我尝试了一个模拟类

id mock = [OCMockObject mockForClass:[MyManagedClass class]];
[[[mock stub] andReturn:@50] getRandomNumber2];
MyManagedClass *my_object = [mock MR_createEntity];

我尝试过使用部分模拟

MyManagedClass *my_object = [MyManagedClass MR_createEntity];
id mock2 = [OCMockObject partialMockForObject:my_object];

在最后一点之后,仅仅创建一个 mock2 的实例就会破坏 my_object 的动态属性,它变得毫无用处。

我也尝试过使用带有我想要存根的函数的模拟协议,但仍然无济于事。

运行时异常是其他人在对 Core Data 对象进行测试时遇到的正常情况:属性不是可识别的选择器。

然而,对我来说奇怪的是,我不是试图存根任何动态属性,而是一个正常的、编译时已知的函数。因此,对我来说,使用 OCMock 会使我的实例变得无用似乎很奇怪。

理想情况下,我想要使用 OCMock/Mogenerator/Magicalrecord 的东西。

我究竟做错了什么?

4

2 回答 2

2

我建议不要尝试模拟托管对象。为了使托管对象工作,有很多运行时的疯狂。这就是为什么我建议使用内存数据库方法进行测试。这将允许您创建实体的空实例,同时让核心数据发生。

由于您可能正在使用单元测试,因此我建议在您认为需要模拟一些数据来重新创建整个堆栈的每个测试用例中,并设置一个具有运行测试所需的状态的新实体。您还可以在内存持久存储中进行测试,与默认堆栈创建方法为您提供的测试分开,并将第二个测试附加到您的默认堆栈。也就是说,创建一个新的内存存储,使用您的假/模拟数据实体对其进行初始化,并将其附加到您的测试数据堆栈。

我希望这个漫无边际的帮助有点,但底线是不要模拟托管对象......真的。

于 2012-10-11T23:21:42.833 回答
0

你可以通过将你的随机数生成移出核心数据对象并进入一个帮助类来做到这一点:

@implementation RandomNumberGenerator

static RandomNumberGenerator *_sharedInstance = nil;

+(RandomNumberGenerator *)sharedInstance {
    if (_sharedInstance == nil) {
        _sharedInstance = [[RandomNumberGenerator alloc] init];
    }    
    return _sharedInstance;
}

+(void)setSharedInstance:(RandomNumberGenerator *)instance {
    [instance retain];
    [_sharedInstance release];
    _sharedInstance = instance;    
}

-(NSNumber *)generateRandomNumber {
    return ...
}

@end

然后在你的测试中:

-(void)testSomething {
    id mockGenerator = [OCMockObject mockForClass:[RandomNumberGenerator class]];
    [RandomNumberGenerator setSharedInstance:mockGenerator];
    [[[mockGenerator stub] andReturn:@(4)] generateRandomNumber];

    MyManagedClass *my_object = [MyManagedClass MR_createEntity];

    expect(my_object.someField).to.equal(someValueBasedOnGeneratedRandomNumber);
}
于 2012-10-11T23:38:57.363 回答