如何设置模拟对象以落实到类别中定义的实际实现?

时间:2014-04-17 08:35:12

标签: objective-c unit-testing ocmock objective-c-category

我有一个带有方法X的objective-c类turtle,我想用OCMock模拟它来对一个类T进行单元测试。

//X.h

@interface X
-(void) turtle;
@end

班级T包含一个类别,并使用该类别与X进行通信。类别方法调用turtle

//X+utils.h:

@interface X(Utils)
-(void) catMethod;
@end

//X+utils.m:
@implementation X(Utils)
-(void) catMethod
{
   [self turtle];
}
@end

//T.m
#import "X+utils.h"

@implementation T
-(void) useX:(X*) xInstance
{
    [xInstance catMethod];
}

在单元测试中,我设置了模拟,希望调用turtle

-(void) test 
{
    id mockX = [OCMockObject mockForClass:[X class]]
    [[mockX expect] turtle];

    [instanceOfT useX:mockX]; 

    [mockX verify];
}

我没有设置模拟以期望调用类别的方法,因为我想让实现自由选择它喜欢使用的任何类别。

调用useX失败,因为OCMock捕获"意外"致电catMethod

我是否可以将OCMock配置为实际使用类别的实现,并且只模拟在实际接口X中定义的调用?

2 个答案:

答案 0 :(得分:1)

这里的关键是你要测试的东西。

在您的测试方法中,您正在测试useX:,此方法的作用。采用纯单元测试方法,您应该测试它在x上调用catMethod

如果你想测试最终调用乌龟,你可以使用类似下面代码的部分模拟。但请记住,您不仅要测试T useX:,还要测试该类别中声明的catMethod

-(void) test 
{
    X *x = [[X alloc] init];
    id partialX = [OCMockObject partialMockForObject:x]
    [[partialX expect] turtle];

    [instanceOfT useX:x]; 

    [partialX verify];
}

答案 1 :(得分:0)

使用-mockForClass:返回一个对象,该对象将对发送给它的任何方法引发异常,而不是您存根或期望的方法。它实际上没有来自指定类的任何实现;它只是伪装成一个实例。 -niceMockForClass:不会引发意外的方法,而只是那些有拒绝的方法,但也不会做任何事情 - 它基本上就像每个方法都有一个空实现的类。

正如在另一个答案中所提到的,你真正想要的是部分模拟,它确实使用了相关类的实际实例。所有方法调用都将调用常规实现,除了那些你存根,期望或拒绝的实现(即使使用那些,你可以使用-andForwardToRealObject来调用原始实现)。