2011-04-14 5 views
16

코어 데이터 모델이 포함 된 프로젝트를 만들었습니다. 응용 프로그램은 모델 파일 (.momd)을 찾고 정상적으로 실행됩니다.단위 테스트에서 코어 데이터 모델 파일을 찾을 수 없습니다.

불행하게도, 단위 테스트는 반환 계속 널 (null) :

NSURL *dataModelURL = [[NSBundle mainBundle] URLForResource:@"myDataModel" withExtension:@"momd"]; 

나는 주요 대상 및 단위 테스트 대상의 컴파일 소스 디렉토리 모두에서 myDataModel.xdatamodeld 폴더와 파일을 볼 수 있습니다 -하지만하지 않는 것 충분 해. 단위 테스트 대상에서 내가 누락 된 부분은 무엇입니까?

감사합니다, -Luther

+1

* 테스트 프로젝트의 * 컴파일 된 소스 목록에 데이터 모델을 추가해야한다는 점에 대해 언급 해 주셔서 감사합니다. 그게 내가 놓친거야. – d512

답변

32

불행하게도 단위 테스트 대상은 응용 프로그램의 기본 번들을 사용하지 않지만 특수 UnitTest 번들을 만듭니다. 따라서 테스트에서 번들 리소스 (예 : 핵심 데이터 모델)를 사용해야하는 경우 해당 문제를 해결해야합니다.

가장 간단하고 가장 유연한 해결 방법은 테스트 코드 내에서 NSBundle이라는 bundleForClass: 방법을 사용하는 것입니다. 해당 방법의 매개 변수는 테스트 중에 [self class]으로 간단하게 지정할 수 있습니다. 그렇게하면 여러 프로젝트에서 번들 식별자를 조정하지 않고도이 코드를 재사용 할 수 있습니다. 예

:

- (void)testBundleLocation 
{ 
    NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 
    NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"]; 
    ... 
} 
+2

마침내! * 오른쪽 * 답변!:) –

+1

@LutherBaker 지금까지는 모든 솔루션 중에서 가장 좋은 해결 방법 인 것처럼 보이지만 이것이 올바른 해결책이라고 생각하지 않습니다. 유닛 테스팅은 어플리케이션 소스를 수정할 필요가 없습니다. 테스트 케이스에서 번들에 접근하는 동안'bundleForClass :'를 실행하는 것은 괜찮은 것으로 보이지만'[NSBundle mainBundle]'(AFAIK가 아니라 공통된 관용구)을 수행하는 애플리케이션 코드가 있다면, , 그 클래스는 단위 테스트를 할 수 없습니다. – Manav

+0

정말 고마워요. 이것을 이해하기 위해 2 일을 놓치지 마십시오! – user798719

6

대답은 번들과 관련이있다. 유닛 테스트 대상은 'main'번들을 사용하지 않습니다. 필자의 경우에는 'com.yourcompany.UnitTest'가 기본값 인 [Target] -info.plist의 자체 번들을 만듭니다.

수정 된 솔루션은 다음과 같습니다

NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.yourcompany.UnitTests"]; 
NSURL *url = [bundle URLForResource:@"myDataModel" withExtension:@"momd"]; 

감사

+0

감사합니다. 필요한 정보 만 있습니다. – theory

+0

이 답변은 문제를 이해하고 해결하는 데 필요한 모든 정보를 제공하기 때문에 좋습니다. –

2

이 방법은 모든 대상에서 번들을 얻을 것이다. 그러나 추가 한 각 대상에 대해 배열에 identifiers 배열에 수동으로 plist 번들 식별자를 추가해야합니다. 프로그래밍 방식으로 얻을 수있는 방법이 없기 때문입니다. 이점은 응용 프로그램을 테스트하거나 실행하는 데 동일한 코드를 사용할 수 있다는 것입니다.

+(NSBundle*) getBundle 
{ 
    NSBundle *bundle = nil; 

    // try your manually set bundles 
    NSArray *identifiers = [NSArray arrayWithObjects: @"com.your.application", 
                 @"com.your.test", 
                 nil]; 
    for(NSString *bundleId in identifiers) { 
     bundle = [NSBundle bundleWithIdentifier:bundleId]; 
     if (bundle!=nil) break; 
    } 

    // try the main bundle 
    if (bundle==nil) bundle = [NSBundle mainBundle]; 

    // abort 
    assert(bundle!=nil && "Missing bundle. Check the Bundle identifier on 
      the plist of this target vs the identifiers array in this class."); 

    return bundle; 
} 
3

내가 OCMock 프레임 워크를 사용하여 그것을 해결, 비슷한 문제가 있었다, 그래서 나는 내 문제는 참으로 잘못된 번들이었다

@interface TestCase() 
    @property (nonatomic, strong) id bundleMock; 
@end 

@implementation TestCase 

- (void)setUp 
{ 
    self.bundleMock = [OCMockObject mockForClass:[NSBundle class]]; 
    [[[self.bundleMock stub] andReturn:[NSBundle bundleForClass:[self class]]] mainBundle]; 
    [super setUp]; 
} 

- (void)tearDown 
{ 
    [self.bundleMock stopMocking]; 
    [super tearDown]; 
} 
0

응용 프로그램 코드를 변경할 필요하지 않았다 ! 프레임 워크 내/내에서 데이터베이스를 사용하려고했기 때문에 단순히 'Bundle'에서 db를로드해야합니다! 여기

는 Swift4에서 일부 코드가 MagicalRecord을 사용하고 있습니다 :

// Load the bundle 
let frameworkBundle = Bundle(for: AClassFromTheFramework.self) 
let managedObjectModel = NSManagedObjectModel.mergedModel(from: [frameworkBundle]) 
// Use the new `managedObjectModel` by default 
MagicalRecord.setShouldAutoCreateManagedObjectModel(false) 
NSManagedObjectModel.mr_setDefaultManagedObjectModel(managedObjectModel) 
// Load the database 
MagicalRecord.setupCoreDataStack(withAutoMigratingSqliteStoreNamed: "db.sqlite") 

봐라!

관련 문제