Как переключиться в хранилище в памяти при выполнении тестов приложений для iOS? - PullRequest
2 голосов
/ 08 декабря 2011

У меня есть довольно стандартный сгенерированный Xcode интерфейс для объектов Core Data, а именно эти свойства в моем делегате приложения:

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

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

  • У меня есть статическая переменная storeType в классе делегата приложения.
  • -persistentStoreCoordinator устанавливает значение NSSQLiteStoreType, если оно nil. Это будет значение по умолчанию, а в производстве значение only гарантирует, что все работает правильно при запуске приложения.
  • Я проверяю, установлен ли макрос DEBUG для всех отладочных сборок (в том числе для моей цели Тесты приложений)
  • Если установлено DEBUG, определите метод в делегате приложения, -resetCoreData. Метод выглядит так:

    #ifdef DEBUG
    - (void)resetCoreData {
        // Testing, we want to use the in memory store.
        storeType = NSInMemoryStoreType;
    
        // Disconnect core data.
        __persistentStoreCoordinator = nil;
        __managedObjectContext = nil;
    
        // Set up defaults.
        [self configureCoreDataDefaults];
    }
    #endif
    

    Обратите внимание, что для статической переменной storeType устанавливается значение NSInMemoryStoreType. Метод -configureCoreDataDefaults создает некоторые управляемые объекты, которые должны присутствовать всегда.

  • В тестовом базовом классе моего приложения у меня есть -setup вызов -resetCoreData:

    - (void)setUp {
        [super setUp];
        [[[UIApplication sharedApplication] delegate] resetCoreData];
    }
    

Это дает мне то, что я хочу: Свежее хранилище основных данных с объектами по умолчанию, созданными для каждого метода тестирования.

Но это раздражает. Я существенно расширил знания о среде тестирования для моего делегата приложения, чтобы он работал по-разному при выполнении тестов приложения. Gross!

Итак, как лучше это сделать? Как вы делаете это?

Ответы [ 2 ]

4 голосов
/ 07 февраля 2012

Продолжение ответа @ eduardo-costa, который я принял, с кодом, который я использовал для его работы.

Сначала я создал класс DAO и переместил туда все основные свойства данных. Файл .h выглядит так:

@interface CollectionsDAO : NSObject

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

+ (CollectionsDAO *)defaultDAO;

@end

Теперь я просто использую этот класс везде, где мне нужно, чтобы получить доступ к своим основным данным. -defaultDAO возвращает статический экземпляр класса, так что я могу использовать его везде. Чего вы не видите, так это частного метода экземпляра -storeType, который возвращает NSSQLiteStoreType. Это используется для создания магазина. Я вернусь к этому ниже.

Далее я создал категорию для этого класса для использования в тестах. Заголовочный файл:

#import "CollectionsDAO.h"

@interface CollectionsDAO (Test)

+ (void)setupTestDAO;
+ (void)clearData;

@end

И реализация:

#import "CollectionsDAO+Test.h"
#include <objc/runtime.h>

static CollectionsDAO *testDAO;
@implementation CollectionsDAO (Testing)

+ (CollectionsDAO *)testDAO {
    if (testDAO == nil) testDAO = [[self alloc] init];
    return testDAO;
}

+ (void)setupTestDAO {
    method_setImplementation(
        class_getClassMethod(self.class, @selector(defaultDAO)),
        method_getImplementation(class_getClassMethod(self.class, @selector(testDAO)))
    );
}

+ (void)clearData {
    testDAO = nil;
}

- (NSString *)storeType {
    return NSInMemoryStoreType;
}

@end

Обратите внимание, что -storeType заменяет закрытый метод с тем же именем по умолчанию, возвращая NSInMemoryStoreType, так что данные будут храниться в памяти.

Теперь, в моем базовом классе тестирования, я просто использую эту категорию следующим образом:

#import "CollectionsDAO+Test.h"

@implementation AppTestBase
+ (void)initialize {
    if (self == AppTestBase.class) {
        [CollectionsDAO setupTestDAO];
    }
}
- (void)tearDown {
    [CollectionsDAO clearData];
}
@end

И теперь тест всегда использует память для хранения данных ядра, экземпляр теста DAO всегда возвращается +defaultDAO (потому что +setupTestDAO меняет его на место), и данные ядра очищаются после каждого теста.

Я думаю, что это много чище, чем у меня было раньше. Мне потребовалось некоторое время, чтобы выяснить это, но ответ Эдуардо был правильным, мне просто пришлось поработать над этим некоторое время, чтобы выяснить детали.

0 голосов
/ 15 января 2012

Я рекомендую создать DAO или аналогичный, чтобы изолировать настройки Core Data. Затем, используя категорию, вы можете определить и использовать эту «resetCoreData» в своей цели теста.

...