Какой самый лучший способ высмеивать коллаборационистов при выполнении BDD в Objective C? - PullRequest
0 голосов
/ 18 февраля 2012

Я работал с Objective C и Cocoa / iOS и тестировал, как издеватель.( Определение )

  • Я хочу смоделировать коллабораторов объекта с помощью OCMock.
  • Есть два способа сделать это в Цели C, о которой я знаю:

    1. Внедрение зависимостей
    2. Установка внутреннего состояния - через Accessors илиsetValue: forKey:

Что мне следует использовать?

Мне не нравится ни один из этих.Но я должен использовать один ... если нет других вариантов, о которых я не знаю.

1.Внедрение зависимостей

Это загромождает мой код, особенно когда SUT имеет 2/3 соавторов.Если SUT необходимо передать 1/2 параметра, все начинает выглядеть очень грязно.

Я понимаю, что за пределами 3 слишком много зависимостей, и объект должен быть разделен на другие части ...но даже с 2 зависимостями и 1 параметром все равно безобразно, как грех.

2.Установка внутреннего состояния

Это портит внутреннее устройство класса, которое, как я думал, было большим нет-нет в тестировании.

Средства доступа определенно отсутствуют - они предоставляют данные, о которых никто не должен знать.Я могу использовать setValue: forKey: ... но это похоже на ужасный взлом.

Это также означает, что я должен инициировать SUT, затем заменить реальных коллабораторов на фиктивных, а затем запустить тестируемый метод,что кажется грязным.

Мой вопрос

Какой самый лучший способ издеваться над сотрудниками в Цели C при выполнении BDD?

Код

Насмешка с использованием setValue: forKey:

@interface JGCompositeCommand : JGCommand <JGCompositeCommandProtocol> {
    NSMutableArray *commands;
    JGCommandFinderFactory *commandFinderFactory;
}

-(id <JGCommandProtocol>)initWithName:(NSString *)name_ recoverer:(id <JGCommandRecoveryProtocol>)recoverer_ executor:(id <JGCommandExecutorProtocol>)executor_;

@end

@implementation JGCompositeCommand

-(id)initWithName:(NSString *)name_ recoverer:(id)recoverer_ {
    self = [super initWithName:name_ recoverer:recoverer_];
    if (self) {
      commands = [NSMutableArray array];
      commandFinderFactory = [[JGCommandFinderFactory alloc] init];
    }
    return self;
}

-(id <JGCommandProtocol>)commandWithName:(NSString *)name_ {
    return [[commandFinderFactory commandFinderWithCommandName:name_ andCommands:commands] findCommandWithName];
}

@end

@interface JGCommandTestCase : SenTestCase {
    JGCompositeCommand *compositeCommand;
    OCMockObject *commandFinderFactoryMock;
}

@end 

@implementation JGCommandTestCase

-(void)setUp {
    [super setUp];
    compositeCommand = [[JGCompositeCommand alloc] initWithName:@"" recoverer:nil];
    commandFinderFactoryMock = [OCMockObject mockForClass:[JGCommandFinderFactory class]];
    // Hack alert! Ugh.
    [compositeCommand setValue:commandFinderFactoryMock forKey:@"commandFinderFactory"];
}

-(void)testGivenCommandNotFoundShouldThrow {
    // ** Setup **
    [[[commandFinderFactoryMock expect] andReturn:...] commandFinderWithCommandName:... andCommands:...];

    // ** Execute **
    [compositeCommand commandWithName:@"Blah"];

    // ** Asserts **
    [commandFinderFactoryMock verify];
}

@end 

1 Ответ

0 голосов
/ 19 февраля 2012

Подход, который мы нашли, состоит в том, чтобы создавать коллабораторы для соавторов и предоставлять способ вставки фиктивного экземпляра во время тестирования:

static JGCommandFinder *sharedFinder = nil;

+(JGCommandFinder *)sharedFinder {
    if (sharedFinder == nil) sharedFinder = [[JGCommandFinder alloc] init];
    return sharedFinder;
}

+(void)setSharedFinder:(JGCommandFinder *)instance {
    sharedFinder = instance;
}

Это очень гибко, поскольку вы можете использовать реальный объектвставьте макет, даже если реальный был инициализирован, и сбросьте его для использования реального объекта, установив для экземпляра значение nil.

...