Почему слабое свойство делегата моего объекта nil в моих модульных тестах? - PullRequest
13 голосов
/ 30 декабря 2011

У меня довольно простая настройка для этого модульного теста. У меня есть класс, который имеет свойство делегата:

@interface MyClass : NSObject
...
@property (nonatomic, weak) id<MyDelegateProtocol> connectionDelegate;
...
@end

и я установил делегата в моем тесте:

- (void)testMyMethod_WithDelegate {
  id delegate = mockDelegateHelper(); // uses OCMock to create a mock object
  [[delegate expect] someMethod];
  myClassIvar.connectionDelegate = delegate;
  [myClass someOtherMethod];
  STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}

Но делегат на самом деле не указан в строке 3 моего модульного теста, поэтому никогда не вызывается #someMethod. Когда я изменяю это на

myClassIvar.connectionDelegate = delegate;
STAssertNotNil(myClassIvar.connectionDelegate, @"delegate should not be nil");

это терпит неудачу там. Я использую ARC, так что я догадывался, что слабая собственность была освобождена. Конечно же, изменение его на strong делает проход STAssertNotNil. Но я не хочу делать это с делегатом, и я не понимаю, почему это имеет значение здесь. Из того, что я прочитал, все локальные ссылки в ARC strong и STAssertNotNil(delegate) проходят. Почему мое слабое свойство делегата равно nil, если того же объекта в локальной переменной нет?

Ответы [ 4 ]

8 голосов
/ 21 февраля 2012

Это ошибка во время выполнения iOS. Следующее обсуждение имеет больше деталей. В двух словах, среда выполнения ARC iOS не может обрабатывать слабые ссылки на прокси. Операционная система OSX может.

http://www.mulle -kybernetik.com / форум / viewtopic.php? Е = 4 & т = 252

Насколько я понимаю из обсуждения, Apple подала отчет об ошибке. Если у кого-то есть разумная идея для обхода проблемы ...

4 голосов
/ 30 января 2012

Я на самом деле не знаю, что здесь происходит, но OCMock возвращает автоматически выпущенный NSProxy -десцендент от метода mockForProtocol:, что я считаю правильным. Может быть, у ARC есть проблемы с NSProxies? Во всяком случае, я преодолел эту проблему, объявив переменную __weak:

- (void)testMyMethod_WithDelegate {
  // maybe you'll also need this modifier inside the helper
  __weak id delegate = mockDelegateHelper(); 
  ...

Это действительно не должно быть __strong (по умолчанию) в этом случае, так как оно автоматически выпущено, и вы не держите его вокруг ...

2 голосов
/ 17 августа 2012

Обходной путь - использовать частичные макеты.

@interface TestMyDelegateProtocolDelegate : NSObject <MyDelegateProtocol>
@end

@implementation TestMyDelegateProtocolDelegate
- (void)someMethod {}
@end


@implementation SomeTest {
- (void)testMyMethod_WithDelegate {
  id<MyDelegateProtocol> delegate = [[TestMyDelegateProtocolDelegate] alloc] init];
  id delegateMock = [OCMockObject partialMockForObject:delegate]
  [[[delegateMock expect] someMethod]
  myClassIvar.connectionDelegate = delegate;
  [myClass someOtherMethod];
  STAssertNoThrow([delegate verify], @"should have called someMethod on delegate.");
}
@end
1 голос
/ 30 декабря 2011

Я не эксперт по ARC, но я предполагаю, что mockDelegateHelper() возвращает слабый объект.В результате delegate равен нулю до выполнения второй строки кода.Рискну предположить, что виновником является либо mockDelegateHelper(), либо OCMock мешает манипулированию и созданию объектов.

...