Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/95.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 使用OCMock、mocking和#x27;可变拷贝';在字符串上_Ios_Ocmock_Gh Unit - Fatal编程技术网

Ios 使用OCMock、mocking和#x27;可变拷贝';在字符串上

Ios 使用OCMock、mocking和#x27;可变拷贝';在字符串上,ios,ocmock,gh-unit,Ios,Ocmock,Gh Unit,我正在尝试在iOS上使用OCMock和GHUnit模拟对mutableCopy的调用 尽管测试通过了,但在清理过程中,我得到了一个EXC\u BAD\u ACCESS异常,我正在试图找出原因 看看这个。此测试表明,可以在模拟的NSString上模拟mutableCopy。在这个测试中,我返回另一个NSString,而不是NSMutableString。这只是为了证明触发了mutableCopy期望,并且测试通过了 #import <GHUnitIOS/GHUnit.h> #impor

我正在尝试在iOS上使用OCMock和GHUnit模拟对
mutableCopy
的调用

尽管测试通过了,但在清理过程中,我得到了一个
EXC\u BAD\u ACCESS
异常,我正在试图找出原因

看看这个。此测试表明,可以在模拟的NSString上模拟
mutableCopy
。在这个测试中,我返回另一个
NSString
,而不是
NSMutableString
。这只是为了证明触发了
mutableCopy
期望,并且测试通过了

#import <GHUnitIOS/GHUnit.h>
#import "OCMock.h"

@interface TestItClass : GHTestCase @end
@implementation TestItClass

// Test that mutableCopy on an NSString is mockable.
- (void)test_1_mutableCopyOfString_shouldBeMockable_givenAStringIsReturned {
    NSString *string = [OCMockObject mockForClass:NSString.class];
    NSString *copy = @"foo";
    [(NSString *) [[(id) string expect] andReturn:copy] mutableCopy];

    // MutableCopy is mocked to return a string, not a mutable string!
    // This is clearly wrong from a static typing point of view, but
    // the test passes anyway, which is ok.
    NSMutableString *result = [string mutableCopy];
    GHAssertEquals(result, copy, nil);
    [(id)string verify];
}
在这两种测试中,验证工作与断言相同。这表明这两个测试都构造得很好,并且模拟预期正在按预期触发。但是,第二次测试在内存访问错误的情况下失败:

Simulator session started with process 7496
Debugger attached to process 7496
2013-03-11 18:23:05.519 UnitTests[7496:c07] TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned ✘ 0.00s
2013-03-11 18:23:06.466 UnitTests[7496:c07] Re-running: TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned <GHTest: 0x7793340>
Exception: EXC_BAD_ACCESS (code=1, address=0x11dfe3ea))
模拟器会话已从进程7496开始
附加到进程7496的调试器
2013-03-11 18:23:05.519单元测试[7496:c07]测试类/测试类字符串的可变副本应为可模拟的,前提是可更改字符串已恢复✘ 0.00s
2013-03-11 18:23:06.466单元测试[7496:c07]重新运行:TestClass/test\u 2\u mutableCopyOfString\u应该是可模拟的\u如果可更改的Strings被重新启动
例外情况:EXC\u错误访问(代码=1,地址=0x11dfe3ea))
你能告诉我为什么会这样吗

谢谢,

我对正在发生的事情有了一点了解。我为自己编译了一个
OCMock
调试库,以便了解崩溃发生的位置

这是我发现的

在我最初的测试中,我调用
andReturn:
来设置返回期望值:

NSMutableString *copy = [@"foo" mutableCopy];
[(NSString *) [[(id) string expect] andReturn:copy] mutableCopy];
这会依次调用
OCMReturnValueProvider
来存储
副本
,以便在适当的时间返回:

@implementation OCMReturnValueProvider

- (id)initWithValue:(id)aValue
{
    self = [super init];
    returnValue = [aValue retain];
    return self;
}
此时,调试器表示
aValue
的类型为
\uu NSCFString
。(警钟在我脑海中响起;这不是一个到底层字符串的免费桥梁吗?不是对
NSMutableString
的引用)

接下来,测试完成并通过

但是,当
OCMReturnValueProvider
dealloc
'd时,现在会出现问题

@implementation OCMReturnValueProvider
- (void)dealloc
{
    [returnValue release];
    [super dealloc];
}
调用
[returnValue release]
时发生崩溃;
OCMReturnValueProvider
正在尝试释放它先前保留的
NSCFString

接下来,我打开了NSZombie调试,这说明:

2013-03-12 20:58:19.654 UnitTests[16667:c07] TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned  
2013-03-12 20:58:21.778 UnitTests[16667:c07] Re-running: TestItClass/test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned <GHTest: 0x4afc5fd0>
2013-03-12 20:58:21.780 UnitTests[16667:c07] *** -[CFString release]: message sent to deallocated instance 0x4b0b1fe0

因此,测试类中的某些内容导致的释放多于保留。为什么会这样?奇怪

经过进一步的调查,我发现了坠机的原因

让我们再看一次测试:

- (void)test_2_mutableCopyOfString_shouldBeMockable_givenAMutableStringIsReturned {
    NSString *string = [OCMockObject mockForClass:NSString.class];
    NSMutableString *copy = [@"foo" mutableCopy];
    [(NSString *) [[(id) string expect] andReturn:copy] mutableCopy];

    NSMutableString *foo = [string mutableCopy];
}
所发生的情况是,编译器假设
[string mutableCopy]
返回的对象被
mutableCopy
保留,因此当
foo
解除分配时,ARC执行与
[foo release]
等效的操作。这是一个问题,因为我们在
andReturn:
中没有增加此对象的引用计数

我不明白为什么我们在配置为由
andReturn:
返回的其他对象上看不到这种行为。处理模拟响应的
OCMReturnValueProvider
未被
ARC
管理,且未保留返回值:

- (void)handleInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setReturnValue:&returnValue];
}
因此,通过在
NSInvocation
中设置返回值之前,先保留返回值,即可解决此问题:

- (void)handleInvocation:(NSInvocation *)anInvocation
{
    [returnValue retain];
    [anInvocation setReturnValue:&returnValue];
}

这看起来像是
OCMock
中的一个bug。但考虑到这个问题并不是在所有情况下都会发生,我不太确定。我的修复程序可以工作,但现在可能会在不需要额外的
retain
的对象上泄漏内存。但是,与未运行的测试相比,测试中的内存泄漏目前是我可以接受的。

您面临的问题是由于ARC遵循以下事实造成的。具体而言:

  • 您拥有您创建的任何对象

    使用名称以“alloc”、“new”、“copy”或“mutableCopy”开头的方法创建对象(例如,alloc、newObject或mutableCopy)

因此,解决方案是查看调用选择器以确定是否保留
returnValue


我希望这有帮助

请在问题中包括您的
-(void)拆卸方法没有明确的拆卸;这只是GHUnit提供的一个库存。@Shineeth实际上,它看起来像是在拆除一个OCMock类。我已经在下面发布了部分答案。你能解释一下你在这次测试中想要达到的目标吗?通常没有任何理由模拟具有良好定义行为的核心API方法。也许有更好的方法来实现你想要测试的东西。嗨,克里斯托弗,当然,我同意。不幸的是,在这种情况下,相对于少量经过良好测试的外部构建器类,从输入生成了一个相当复杂的输出字符串。我不希望这些的实现细节成为使用它们的类的测试的考虑因素。这就要求我用可变字符串模拟它们的交互,可变字符串正在累积它们的效果。不理想,但我不愿意放弃对关注点的封装。我已经向OCMock的维护人员提出了此修复方案。一旦问题得到解决,我会在这里汇报。我相信问题在于mutableCopy有点特殊。通常,调用者有责任保留他们想要保留的对象。被调用的方法返回具有“中性”保留计数的对象。然而,MutableCopy返回一个带有+1保留计数的对象。我看到了pull请求,但会尝试找到一个不会泄漏内存的解决方案;对于创建对象的方法,OCMock的行为不正常。我现在有
- (void)handleInvocation:(NSInvocation *)anInvocation
{
    [anInvocation setReturnValue:&returnValue];
}
- (void)handleInvocation:(NSInvocation *)anInvocation
{
    [returnValue retain];
    [anInvocation setReturnValue:&returnValue];
}