Xcode:TEST 与 DEBUG 预处理器宏

发布于 2024-11-25 04:47:39 字数 642 浏览 2 评论 0原文

使用单元测试创​​建新项目时,Xcode 将测试方案的构建配置设置为“调试”(与“运行”方案相同)。

我应该区分运行(Command-R)和运行(Command-R)吗?测试(Command-U)方案?

即,我是否应该创建一个名为 Test 的新构建配置,向其中添加预处理器宏 TEST=1,并将其用作测试方案的构建配置?或者,我应该保留 Run & 吗?测试两者作为调试?

我有 Ruby/Rails 背景,通常有测试、开发和生产环境。在我看来,调试就像开发,发布就像生产,但是我们缺少测试,这就是为什么我认为添加测试可能是有意义的。

评论?意见?建议?

我特别问这个问题是因为我想编译一些东西来进行测试:

#ifdef TEST
// Do something when I test.
#endif

我认为如果我也编译它来进行调试并不重要。所以,我真的可以这样做:

#ifdef DEBUG
// Do something when I run or test.
#endif

但是,我现在真的只想做测试。所以,这就是为什么我认为我应该区分调试和调试。测试但我想知道为什么 Xcode 默认情况下不为你这样做?苹果是否认为你不应该区分它们?

When creating a new project with unit tests, Xcode sets the build configuration to Debug for the Test scheme (same for the Run scheme).

Should I differentiate between Run (Command-R) & Test (Command-U) schemes?

I.e., should I create a new Build Configuration called Test, add a preprocessor macro TEST=1 to it, and use it as the build configuration for the Test scheme instead? Or, should I just keep Run & Test both as Debug?

I come from a Ruby/Rails background, where you usually have test, development, and production environments. It seems to me that Debug is like development and Release is like production, but we're missing a test, which is why I'm thinking it might make sense to add Test.

Comments? Opinions? Suggestions?

I'm specifically asking this because I want to compile something for Test with:

#ifdef TEST
// Do something when I test.
#endif

I don't think it matters if I also compile this for Debug. So, I really could just do:

#ifdef DEBUG
// Do something when I run or test.
#endif

But, I'm really only intending to do it for tests for now. So, that's why I'm thinking I should differentiate between debug & test but am wondering why Xcode doesn't do that for you by default? Does Apple think you shouldn't differentiate between them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

玉环 2024-12-02 04:47:39

预处理器宏将不起作用,您需要在运行时检查环境。

Objective-c

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    return (environment[@"XCTestConfigurationFilePath"] != nil);
}

Swift

var unitTesting : Bool 
{
    return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}

(针对 Xcode 11 进行了更新)

Preprocessor macros will not work, you need to check the environment at runtime.

Objective-c

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    return (environment[@"XCTestConfigurationFilePath"] != nil);
}

Swift

var unitTesting : Bool 
{
    return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}

(Updated for Xcode 11)

骷髅 2024-12-02 04:47:39

您可以考虑添加新的构建配置。

在 Xcode 4 中,单击左侧导航器上的项目。

在主窗口中,单击您的项目,然后选择“信息”选项卡。

单击“+”按钮添加新配置(如果您愿意,您可以将其称为“测试”)。

现在,单击您的目标,然后转到构建设置选项卡。

搜索“预处理器宏”,

在这里,您可以为您的新构建配置添加预处理器宏。

只需双击新的“测试”配置,然后添加 TESTING=1。

最后,为您的方案选择测试选项。选择您的“测试”。 配置。

You might consider adding a new build configuration.

In xcode 4, click on your project on the left hand navigator.

In the main window, click on your project, and then select the "info" tab.

Click the "+" button to add a new configuration (you can call yours "test" if you like").

Now, click on your target, and go to the build settings tab.

Search for "preprocessor macros"

Here, you can add preprocessor macros for your new build configuration.

Just double click on your new "test" configuration, and add TESTING=1.

Finally, edit your build scheme. Select the test options for your scheme. There should be a "Build Configuration" drop down menu. Select your "test" configuration.

场罚期间 2024-12-02 04:47:39

我没有创建测试构建配置,而是:

  1. 创建了一个 Tests-Prefix.pch 文件:

    <前><代码>#define 测试 1
    #import
    #import“CocoaPlant-Prefix.pch”

  2. 在测试目标的构建设置的“前缀标头”字段中输入了其路径。

  3. 将以下代码添加到我创建的名为 MyAppDefines.h 的文件顶部,并在 MyApp-Prefix.pch 中导入:

    <前><代码>#ifdef 测试
    #define TEST_CLASS NSClassFromString(@"AppDelegateTests") // 任何测试类
    #define BUNDLE [NSBundle bundleForClass:TEST_CLASS]
    #define APP_NAME @"测试"
    #别的
    #define BUNDLE [NSBundle mainBundle]
    #define APP_NAME [[BUNDLE infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]
    #endif

这允许我在我的意思是 [NSBundle mainBundle] 的地方使用 BUNDLE 并且在运行测试时让它工作。

Tests-Prefix.pch 中导入 SenTestingKit 还可以加快 SenTestingKit 框架的编译速度,并允许我从顶部省略 #import所有测试文件。

Instead of creating a Test build configuration, I:

  1. created a Tests-Prefix.pch file:

    #define TEST 1
    #import <SenTestingKit/SenTestingKit.h>
    #import "CocoaPlant-Prefix.pch"
    
  2. entered its path in the Prefix Header field of the Tests target's build settings.

  3. added the following code to the top of a file I created called MyAppDefines.h, imported in MyApp-Prefix.pch:

    #ifdef TEST
    #define TEST_CLASS NSClassFromString(@"AppDelegateTests") // any test class
    #define BUNDLE [NSBundle bundleForClass:TEST_CLASS]
    #define APP_NAME @"Tests"
    #else
    #define BUNDLE [NSBundle mainBundle]
    #define APP_NAME [[BUNDLE infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]
    #endif
    

This allows me to use BUNDLE where ever I mean [NSBundle mainBundle] and also have it work when I run Tests.

Importing SenTestingKit in Tests-Prefix.pch also speeds up the compiling of the SenTestingKit Framework and allows me to leave out #import <SenTestingKit/SenTestingKit.h> from the top of all the tests files.

终陌 2024-12-02 04:47:39

我决定在代码本身中添加对环境变量的检查,而不是使用 Robert 提出的 isRunningTests() 建议。

  1. 编辑当前方案(产品/方案/编辑方案)或 Command+<
  2. 单击测试配置
  3. 单击参数取消选中“使用运行操作的参数和环境变量
  4. 展开环境变量部分并添加值为 YES 的变量 TESTING
  5. 将其添加到代码中的某处,并在需要时调用:
 + (BOOL) 正在测试
    {
        NSDictionary* 环境 = [[NSProcessInfo processInfo] 环境];
        return [环境 objectForKey:@"TESTING"] != nil;
    }

完成后屏幕应如下所示。

屏幕应该如下所示

上面的代码在测试模式或应用程序模式下运行时将查找 TESTING 环境变量。该代码位于您的应用程序中,而不是单元测试文件中。您可以使用

#ifdef DEBUG
...
#endif

来防止代码在生产中执行。

I decided to add a check for an environment variable in the code itself, instead of using the isRunningTests() suggestion Robert made.

  1. Edit the current Scheme (Product/Scheme/Edit Scheme) or Command+<
  2. Click on the Test configuration
  3. Click on Arguments Uncheck "Use the Run action's arguments and environment variables
  4. Expand Environment Variable section and add the variable TESTING with value YES
  5. Add this to your code somewhere and call is whenever you need to:
 + (BOOL) isTesting
    {
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        return [environment objectForKey:@"TESTING"] != nil;
    }

The screen should look like this when you are done.

The screen should look like this

The code above will find the TESTING environment variable when running in test mode or application mode. This code goes in your application, not the unit test files. You can use

#ifdef DEBUG
...
#endif

To prevent the code from being executed in production.

清眉祭 2024-12-02 04:47:39

如果您创建一个测试构建配置,然后将目标的“其他 Swift 标志”属性设置为“-DTEST”,它将定义一个可在您的 swift 代码中工作的 TEST 宏。确保在应用程序目标的构建设置中进行设置,以便可以在应用程序的 Swift 代码中使用它。

其他 Swift 标志设置 DEBUG 和 TEST

然后使用此设置,您可以像这样测试您的代码:

func testMacro() {
   #if !TEST 
       // skipping over this block of code for unit tests
   #endif
}

If you create a Test build configuration and then set the "Other Swift Flags" property of your Target to "-DTEST" it will define a TEST macro that will work in your swift code. Make sure you set it in the build settings of your App target so that you can use it in your App's Swift code.

Other Swift Flags setting for DEBUG and TEST

Then with this set, you can test your code like so:

func testMacro() {
   #if !TEST 
       // skipping over this block of code for unit tests
   #endif
}
×眷恋的温暖 2024-12-02 04:47:39

罗伯特在 SWIFT 3.0 中的回答:

func isRunningTests() -> Bool {
    let environment = ProcessInfo().environment
    return (environment["XCInjectBundleInto"] != nil);
}

Robert's answer in SWIFT 3.0:

func isRunningTests() -> Bool {
    let environment = ProcessInfo().environment
    return (environment["XCInjectBundleInto"] != nil);
}
久隐师 2024-12-02 04:47:39

我测试了这么长时间,发现了一个结果:

不仅你将预处理器宏添加到你的单元测试目标中(你可以有很多方法
仅使用变量进行单元测试
并遵循 @MattDiPasquale 方法),

而且您还必须在测试目标中添加条件编译文件。
我们应该重新编译这个文件,因为这个文件有一个新的预处理器宏,
但此文件已内置于您的预处理器宏未设置时的应用程序目标中。

希望这对您有帮助。

I test such a long time, found a result:

Not only you add the preproessor macro into your unit test target(You could have many methods
using variables for unit testing only,
and follow the @MattDiPasquale methods),

but also You must add the condition complie file in your test target.
we should recomplie this file, because you have a new preprocessor macro for this file,
but this file has built in the application target that time your preprocessor macro didn't set.

Hope this help you.

混吃等死 2024-12-02 04:47:39

针对 Xcode10 进行了更新:

static let isRunningUnitTests: Bool = {
    let environment = ProcessInfo().environment
    return (environment["XCTestConfigurationFilePath"] != nil)
}()

Updated for Xcode10:

static let isRunningUnitTests: Bool = {
    let environment = ProcessInfo().environment
    return (environment["XCTestConfigurationFilePath"] != nil)
}()
风吹雨成花 2024-12-02 04:47:39

查看环境变量以查看单元测试是否正在运行。与罗伯特的回答类似,但为了性能我只检查一次。

+ (BOOL)isRunningTests {
   static BOOL runningTests;
   static dispatch_once_t onceToken;

   // Only check once
   dispatch_once(&onceToken, ^{
      NSDictionary* environment = [[NSProcessInfo processInfo] environment];
      NSString* injectBundle = environment[@"XCInjectBundle"];
      NSString* pathExtension = [injectBundle pathExtension];
      runningTests = ([pathExtension isEqualToString:@"octest"] ||
                      [pathExtension isEqualToString:@"xctest"]);
   });
   return runningTests;
}

Look at environment variables to see if unit tests are running. Similar to Robert's answer but I only check once for performance sake.

+ (BOOL)isRunningTests {
   static BOOL runningTests;
   static dispatch_once_t onceToken;

   // Only check once
   dispatch_once(&onceToken, ^{
      NSDictionary* environment = [[NSProcessInfo processInfo] environment];
      NSString* injectBundle = environment[@"XCInjectBundle"];
      NSString* pathExtension = [injectBundle pathExtension];
      runningTests = ([pathExtension isEqualToString:@"octest"] ||
                      [pathExtension isEqualToString:@"xctest"]);
   });
   return runningTests;
}
鹿港小镇 2024-12-02 04:47:39

在 iOS 上,当单元测试运行时,[UIApplication sharedApplication] 将返回 nil

On iOS, [UIApplication sharedApplication] will return nil when a unit test is running.

許願樹丅啲祈禱 2024-12-02 04:47:39

Kev 答案的修改版本适用于 Xcode 8.3.2

+(BOOL)isUnitTest {

    static BOOL runningTests;
    static dispatch_once_t onceToken;

    // Only check once
    dispatch_once(&onceToken, ^{
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        if (environment[@"XCTestConfigurationFilePath"] != nil && ((NSString *)environment[@"XCTestConfigurationFilePath"]).length > 0) {
            runningTests = true;
        } else {
            runningTests = false;
        }
    });
    return runningTests;
}

Modified version of Kev's answer that works for me on Xcode 8.3.2

+(BOOL)isUnitTest {

    static BOOL runningTests;
    static dispatch_once_t onceToken;

    // Only check once
    dispatch_once(&onceToken, ^{
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        if (environment[@"XCTestConfigurationFilePath"] != nil && ((NSString *)environment[@"XCTestConfigurationFilePath"]).length > 0) {
            runningTests = true;
        } else {
            runningTests = false;
        }
    });
    return runningTests;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文