简体   繁体   English

调用[NSBundle mainBundle]时XCTest失败

[英]XCTest fails when calling [NSBundle mainBundle]

I have some code that calls [NSBundle mainBundle] at some point, mainly to read/set preferences. 我有一些代码在某些时候调用[NSBundle mainBundle] ,主要是读取/设置首选项。 When I unit test the method, the test fails because the test's mainBundle does not contain the file. 当我对方法进行单元测试时,测试失败,因为测试的mainBundle不包含该文件。

This is a known issue , that Apple won't fix as they consider it is not a bug : 这是一个众所周知的问题 ,Apple不会修复,因为他们认为这不是一个bug

the gist of their reply is that XCTest is working correctly by returning it's own main bundle instead of the bundle of the test target. 他们回复的要点是XCTest通过返回它自己的主bundle而不是测试目标的bundle来正常工作。

Previously our codebase was using a category override on NSBundle 's +mainBundle class method to work around this. 以前我们的代码库在NSBundle+mainBundle类方法上使用类别覆盖来解决这个问题。 But this is dangerous because the behaviour of overriding an existing method in a category is undefined . 但这很危险,因为覆盖类别中现有方法的行为是未定义的

If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. 如果在类别中声明的方法的名称与原始类中的方法相同,或者在同一个类(或甚至是超类)上的另一个类别中的方法相同,则关于在哪个方法实现中使用哪个方法实现的行为是未定义的。运行。

Actually Xcode warns you about it: 实际上Xcode警告你:

Category is implementing a method which will also be implemented by its primary class 类别正在实施一种方法,该方法也将由其主要类实现

So, what is the proper method to address the issue? 那么,解决这个问题的正确方法是什么?

The simplest and cleanest way of fixing this issue is to partially mock the NSBundle class in your unit tests to return [NSBundle bundleForClass:[self class]] when you call [NSBundle mainBundle] . 解决此问题的最简单和最[NSBundle bundleForClass:[self class]]在您调用[NSBundle mainBundle]时,在单元测试中部分模拟NSBundle类以返回[NSBundle bundleForClass:[self class]] [NSBundle mainBundle]

You may put this in your -setup method so that it is mocked for your entire test class: 您可以将它放在-setup方法中,以便为整个测试类进行-setup

static id _mockNSBundle;

@implementation MyTests

- (void)setUp
{
  [super setUp];

  _mockNSBundle = [OCMockObject niceMockForClass:[NSBundle class]];
  NSBundle *correctMainBundle = [NSBundle bundleForClass:self.class];
  [[[[_mockNSBundle stub] classMethod] andReturn:correctMainBundle] mainBundle];
}

@end

Nice and clean. 干净整洁。

[ Source ] [ 来源 ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM