如何运行和调试iPhone应用程序的单元测试

时间:2022-10-15 20:29:42

NOTE: Unit testing is a lot easier to setup nowadays. This tutorial is not really relevant for Xcode version 5 and above.

注意:现在单元测试更容易设置。本教程与Xcode版本5及更高版本无关。

It took me quite some time but I finally managed to make it work for my project. To create the "logic" tests I followed Apple guidelines on creating logic tests. This works fine once you understand that the logic tests are run during build.

我花了很长时间,但我终于设法使它适用于我的项目。为了创建“逻辑”测试,我遵循Apple关于创建逻辑测试的指导原则。一旦您了解在构建期间运行逻辑测试,这就可以正常工作。

To be able to debug those tests it is required to create a custom executable that will call those tests. The article by Sean Miceli on the Grokking Cocoa blog provides all the information to do this. Following it however did not yield immediate success and needed some tweaking.

为了能够调试这些测试,需要创建一个可以调用这些测试的自定义可执行文件。 Sean Miceli在Grokking Cocoa博客上的文章提供了所有这些信息。然而,它并没有立即取得成功,需要进行一些调整。

I will go over the main steps presented in Sean's tutorial providing some "for dummies" outline which took me some time to figure out:

我将介绍Sean教程中提供的主要步骤,提供一些“for dummies”大纲,这花了我一些时间来弄清楚:

  1. Setup a target that contains the unit tests but DOES NOT run them
  2. 设置包含单元测试的目标但不运行它们
  3. Setup the otest executable to run the tests
  4. 设置otest可执行文件以运行测试
  5. Setup the otest environment variables so that otest can find your unit tests
  6. 设置otest环境变量,以便otest可以找到您的单元测试

The following was performed with XCode 3.2.5

使用XCode 3.2.5执行以下操作

Note for XCode 4

In XCode 4 it is possible to debug your unit tests DIRECTLY. Just write your test, add it to your target as one of the tests and set a breakpoint in it. That's all. More will come.

在XCode 4中,可以直接调试单元测试。只需编写测试,将其作为测试之一添加到目标中,并在其中设置断点。就这样。会有更多。

Step 1 - Setting up the target

  1. Duplicate your unit tests target located under your project Targets. This will also create a duplicate of your unit tests product (.octest file). In the figure below "LogicTest" is the original target.
  2. 复制位于项目目标下的单元测试目标。这也将创建单元测试产品(.octest文件)的副本。在下图中,“LogicTest”是原始目标。
  3. Rename both the unit tests target and the unit tests product (.octest file) to the same name. In the figure below "LogicTestsDebug" is the duplicate target.
  4. 将单元测试目标和单元测试产品(.octest文件)重命名为相同的名称。在下图中,“LogicTestsDebug”是重复的目标。
  5. Delete the RunScript phase of the new target
  6. 删除新目标的RunScript阶段

The name of both can be anything but I would avoid spaces.

两者的名字可以是任何东西,但我会避免空格。

如何运行和调试iPhone应用程序的单元测试

Step 2 - Setting up otest

The most important point here is to get the correct otest, i.e. the one for your current iOS and not the default Mac version. This is well described in Sean's tutorial. Here are a few more details which helped me setting things right:

这里最重要的一点是获得正确的otest,即您当前的iOS而不是默认的Mac版本。这在Sean的教程中有详细描述。以下是一些有助于我正确设置的细节:

  1. Go Project->New Custom Executable. This will pop open a window prompting you to enter an Executable Name and an Executable Path.
  2. Go Project-> New Custom Executable。这将弹出一个窗口,提示您输入可执行文件名和可执行文件路径。
  3. Type anything you wish for the name.
  4. 输入您想要的任何名称。
  5. Copy paste the path to your iOS otest executable. In my case this was /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest
  6. 复制粘贴到iOS otest可执行文件的路径。在我的例子中,这是/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest
  7. Press enter. This will bring you to the configuration page of your executable.
  8. 按enter键。这将带您进入可执行文件的配置页面。
  9. The only thing to change at this point is to select "Path Type: Relative to current SDK". Do not type in the path, this was done at step 3. 如何运行和调试iPhone应用程序的单元测试
  10. 此时唯一要改变的是选择“路径类型:相对于当前SDK”。不要输入路径,这是在步骤3完成的。

Step 3 - Setting up the otest arguments and environment variables

The otest arguments are straightforward to setup... But this proved to be my biggest problem. I initially had named my logic test target "LogicTests Debug". With this name and "LogicTests Debug.octest" (with quotes) as argument to otest I kept having otest terminating with exit code 1 and NEVER stopping into my code...

讽刺的论点很容易设置......但事实证明这是我最大的问题。我最初将我的逻辑测试目标命名为“LogicTests Debug”。使用此名称和“LogicTests Debug.octest”(带引号)作为otest的参数,我保持otest以退出代码1终止并且永远不会停止进入我的代码......

The solution: no space in your target name!

解决方案:目标名称中没有空格!

The arguments to otest are:

otest的论据是:

  1. -SenTest Self (or All or a test name - type man otest in terminal to get the list)
  2. -SenTest Self(或全部或测试名称 - 在终端中键入man otest以获取列表)
  3. {LogicTestsDebug}.octest - Where {LogicTestsDebug} needs to be replaced by your logic test bundle name.
  4. {LogicTestsDebug} .octest - 需要用逻辑测试包名称替换{LogicTestsDebug}。

Here is the list of environment variables for copy/pasting:

以下是复制/粘贴的环境变量列表:

  • DYLD_ROOT_PATH: $SDKROOT
  • DYLD_ROOT_PATH:$ SDKROOT
  • DYLD_FRAMEWORK_PATH: "${BUILD_PRODUCTS_DIR}: ${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}"
  • DYLD_FRAMEWORK_PATH:“$ {BUILD_PRODUCTS_DIR}:$ {SDK_ROOT}:$ {DYLD_FRAMEWORK_PATH}”
  • IPHONE_SIMULATOR_ROOT: $SDKROOT
  • IPHONE_SIMULATOR_ROOT:$ SDKROOT
  • CFFIXED_USER_HOME: "${HOME}/Library/Application Support/iPhone Simulator/User"
  • CFFIXED_USER_HOME:“$ {HOME} /图书馆/应用程序支持/ iPhone模拟器/用户”
  • DYLD_LIBRARY_PATH: ${BUILD_PRODUCTS_DIR}:${DYLD_LIBRARY_PATH}
  • DYLD_LIBRARY_PATH:$ {BUILD_PRODUCTS_DIR}:$ {DYLD_LIBRARY_PATH}
  • DYLD_NEW_LOCAL_SHARED_REGIONS: YES
  • DYLD_NEW_LOCAL_SHARED_REGIONS:是的
  • DYLD_NO_FIX_PREBINDING: YES
  • DYLD_NO_FIX_PREBINDING:是的

Note that I also tried the DYLD_FORCE_FLAT_NAMESPACE but this simply made otest crash.

请注意,我也尝试过DYLD_FORCE_FLAT_NAMESPACE,但这只是造成了*。

如何运行和调试iPhone应用程序的单元测试

Step 4 - Running your otest executable

To run your otest executable and start debugging your tests you need to:

要运行您的otest可执行文件并开始调试您的测试,您需要:

  1. Set your active target to your unit test target (LogicTestsDebug in my case)
  2. 将活动目标设置为单元测试目标(在我的情况下为LogicTestsDebug)
  3. Set your active executable to your otest executable
  4. 将活动可执行文件设置为您的可执行文件

You can build and run your executable and debug your tests with breakpoints.

您可以使用断点构建和运行可执行文件并调试测试。

As a side note if you are having problems running your otest executable it can be related to:

作为旁注,如果您在运行otest可执行文件时遇到问题,则可能与以下内容有关:

  1. Faulty path. I had lots of problem initially because I was pointing to the mac otest. I kept crashing on launch with termination code 6.
  2. 路径错误。我最初有很多问题,因为我指的是mac otest。我一直在使用终止代码6启动时崩溃。
  3. Faulty arguments. Until I removed the space from bundle (.octest) name I kept having otest crash with exit code 1.
  4. 错误的论点。直到我从bundle(.octest)名称中删除了空格,我一直在使用退出代码1进行*。
  5. Wrong path in environment variables. Sean tutorial has lots of follow-up questions giving some insight on what other people tried. The set I have now seems to work so I suggest you start with this.
  6. 环境变量中的路径错误。肖恩教程有很多后续问题,可以提供一些其他人尝试过的见解。我现在的套装似乎工作,所以我建议你从这开始。

You may get some message in the console which might lead you to think something is wrong with your environment variables. You may notice a message regarding CFPreferences. This message is not preventing the tests from running properly so don't focus on it f you have problems running otest.

您可能会在控制台中收到一些消息,这些消息可能会导致您认为环境变量存在问题。您可能会注意到有关CFP参考的消息。此消息不会阻止测试正常运行,因此如果您在运行otest时遇到问题,请不要关注它。

如何运行和调试iPhone应用程序的单元测试

Last once everything is working you will be able to stop at breakpoints in your tests.

一旦一切正常,您将能够在测试中的断点处停下来。

如何运行和调试iPhone应用程序的单元测试

One last thing...

I've read on many blogs that the main limitation of the integrated XCode SenTestKit is that tests cannot be run while building the application. Well as it turns out this is in fact quite easy to manage. You simply need to add your Logic tests bundle as a dependency to your application project. This will make sure your logic tests bundle is built, i.e. all tests are run, before your application is built.

我在很多博客上都看到,集成的XCode SenTestKit的主要限制是在构建应用程序时无法运行测试。事实证明这实际上很容易管理。您只需将Logic测试包添加为应用程序项目的依赖项。这将确保在构建应用程序之前构建逻辑测试包,即运行所有测试。

To do this you can drag and drop your logic test bundle onto your application target.

为此,您可以将逻辑测试包拖放到应用程序目标上。

如何运行和调试iPhone应用程序的单元测试

2 个解决方案

#1


7  

This post is intended as a "How-to" more than a real question. Therefore this answer is just meant to allow me to mark the "How-to" as "answered". This will probably be flagged by the community as irregular. I'm up for suggestions on where to post future "How-to" articles.

这篇文章的目的是作为一个“操作方法”,而不是一个真正的问题。因此,这个答案只是为了让我将“操作方法”标记为“已回答”。这可能会被社区标记为不规则。我想知道在哪里发布未来的“操作方法”文章。

One final note though on this topic. For those who still wonder whether writing unit tests is worth it I would definitely say Yes!

关于这个主题的最后一点说明。对于那些仍然怀疑写单元测试是否值得的人我肯定会说是的!

I am currently writing an application with CoreData and retrieval of data from a web service (xml parsing). The complete model can be tested and debugged without having to:

我目前正在使用CoreData编写应用程序并从Web服务检索数据(xml解析)。可以测试和调试完整的模型,而无需:

  1. run the actual application on the simulator or device. Not having to use the device to run the tests is a huge gain of time. It's the difference between 2 minutes and 5 seconds per run.
  2. 在模拟器或设备上运行实际应用程序。不必使用该设备来运行测试是一个巨大的时间。这是每次运行2分钟到5秒之间的差异。
  3. without the need to create views or controllers when testing the model. The complete development and testing can focus on the model only in the first iteration. Once the model is cleared for integration the rest of the development can follow.
  4. 在测试模型时无需创建视图或控制器。完整的开发和测试只能在第一次迭代中关注模型。一旦模型被清除以进行集成,其余的开发可以遵循。

To debug the xml parsing I can simply use "hard-coded" files which I completely control.

要调试xml解析,我可以简单地使用我完全控制的“硬编码”文件。

The crux is of course to write the tests as you implement features in the code. It really is a time saver down the line in terms of debugging of the complete application.

当然,关键是在代码中实现功能时编写测试。在整个应用程序的调试方面,它确实节省了时间。

Voilà, I'll leave it at that.

沃利亚,我会留下它。

#2


0  

I was able to run the test case in debugger in the following simple steps:

我能够通过以下简单步骤在调试器中运行测试用例:

  1. Product > Build For > Testing
  2. 产品>构建>测试
  3. Put a break point in part of the test you want to debug
  4. 在要调试的测试的一部分中放置一个断点
  5. Product > Test
  6. 产品>测试

This is on Xcode 6.0.1 and seems much more convenient than the long procedure described above.

这是在Xcode 6.0.1上,看起来比上面描述的长程序更方便。

#1


7  

This post is intended as a "How-to" more than a real question. Therefore this answer is just meant to allow me to mark the "How-to" as "answered". This will probably be flagged by the community as irregular. I'm up for suggestions on where to post future "How-to" articles.

这篇文章的目的是作为一个“操作方法”,而不是一个真正的问题。因此,这个答案只是为了让我将“操作方法”标记为“已回答”。这可能会被社区标记为不规则。我想知道在哪里发布未来的“操作方法”文章。

One final note though on this topic. For those who still wonder whether writing unit tests is worth it I would definitely say Yes!

关于这个主题的最后一点说明。对于那些仍然怀疑写单元测试是否值得的人我肯定会说是的!

I am currently writing an application with CoreData and retrieval of data from a web service (xml parsing). The complete model can be tested and debugged without having to:

我目前正在使用CoreData编写应用程序并从Web服务检索数据(xml解析)。可以测试和调试完整的模型,而无需:

  1. run the actual application on the simulator or device. Not having to use the device to run the tests is a huge gain of time. It's the difference between 2 minutes and 5 seconds per run.
  2. 在模拟器或设备上运行实际应用程序。不必使用该设备来运行测试是一个巨大的时间。这是每次运行2分钟到5秒之间的差异。
  3. without the need to create views or controllers when testing the model. The complete development and testing can focus on the model only in the first iteration. Once the model is cleared for integration the rest of the development can follow.
  4. 在测试模型时无需创建视图或控制器。完整的开发和测试只能在第一次迭代中关注模型。一旦模型被清除以进行集成,其余的开发可以遵循。

To debug the xml parsing I can simply use "hard-coded" files which I completely control.

要调试xml解析,我可以简单地使用我完全控制的“硬编码”文件。

The crux is of course to write the tests as you implement features in the code. It really is a time saver down the line in terms of debugging of the complete application.

当然,关键是在代码中实现功能时编写测试。在整个应用程序的调试方面,它确实节省了时间。

Voilà, I'll leave it at that.

沃利亚,我会留下它。

#2


0  

I was able to run the test case in debugger in the following simple steps:

我能够通过以下简单步骤在调试器中运行测试用例:

  1. Product > Build For > Testing
  2. 产品>构建>测试
  3. Put a break point in part of the test you want to debug
  4. 在要调试的测试的一部分中放置一个断点
  5. Product > Test
  6. 产品>测试

This is on Xcode 6.0.1 and seems much more convenient than the long procedure described above.

这是在Xcode 6.0.1上,看起来比上面描述的长程序更方便。