单元测试Xcode中的私有方法

时间:2009-07-08 14:46:01

标签: objective-c cocoa xcode tdd ocunit

我正在尝试玩具项目中的测试驱动开发。我可以让我的类的公共接口的测试工作(虽然我仍然在使用,因为我编写的测试代码比测试的方法更多)。

我倾向于使用很多私有方法,因为我喜欢保持公共接口干净;但是,我还是想对这些方法进行测试。

由于Cocoa是一种动态语言,我仍然可以调用这些私有方法,但是在我的测试中我得到警告,我的班级可能不会对这些方法做出反应(尽管很明显)。由于我喜欢在没有任何警告的情况下进行编译,因此我的问题是:

  1. 如何在Xcode中关闭这些警告?
  2. 我还能做些什么来关闭这些警告吗?
  3. 我在尝试'白盒'测试时做错了吗?

7 个答案:

答案 0 :(得分:125)

请记住,在Objective-C中实际上没有“私有方法”,这不仅仅是因为它是一种动态语言。根据设计,Objective-C具有适用于ivars的可见性修饰符,但不适用于方法 - 您可以调用任何您喜欢的方法,这不是偶然的。

@Peter 的建议很棒。为了补充他的答案,我使用的替代方案(当我不想/需要仅用于私有方法的标题时)是在单元测试文件本身中声明一个类别。 (我使用@interface MyClass (Test)作为名称。)这是添加在发布代码中不必要膨胀的方法的好方法,例如用于访问被测试类可以访问的ivars。 (当使用属性时,这显然不是问题。)

我发现这种方法可以轻松公开和验证内部状态,以及添加仅测试方法。例如,在this unit test file中,我编写了一个-isValid方法来验证二进制堆的正确性。在生产中,这种方法会浪费空间,因为我假设堆是有效的 - 如果我修改代码,我在测试单元测试回归时只关心它。

答案 1 :(得分:89)

  

如何在Xcode中关闭这些警告?

别。

  

我可以采取其他措施来关闭这些警告吗?

别。

  

我在尝试'白盒'测试时做错了什么?

没有

解决方案是将您的私有方法移动到其自己的标头中的类别。将此标头导入实际类和测试用例类实现文件。

答案 2 :(得分:4)

看起来另一个问题有答案:Is there a way to suppress warnings in Xcode?

答案 3 :(得分:3)

虽然拥有私有标头或定义自己的类别可能是更正确的解决方案,但还有另一个非常简单的解决方案:在调用方法之前将对象强制转换为(id)。

答案 4 :(得分:3)

如果您不希望在多个源文件中分发您的私有方法实现,则对Category解决方案的一个改进是在头文件中定义一个扩展(实质上是一个匿名类别 - 引用Apple's documentation)由现有类的实现和相关的单元测试源文件导入。

使用扩展允许编译器在主@implementation块中不存在私有方法的实现时发出警告。 This link很好地说明了这一点。

答案 5 :(得分:3)

几天前,当我开始使用TDD时,我正在处理同样的问题。我在Test-Driven iOS Development书中找到了这个非常有趣的观点:

  

我经常被问到,“我应该测试我的私人方法吗?”或相关问题“我应该如何测试我的私人方法?”人们问第二个问题假设第一个问题的答案是“是”并且现在正在寻找一种方法来在他们的测试套件中公开他们的类的私有接口。

     

我的回答依赖于观察一个微妙的事实:你已经测试了你的私人方法。通过遵循测试驱动开发中常见的红绿重构方法,您设计了对象的公共API来完成这些对象需要执行的工作。通过测试指定的工作 - 并继续执行测试,确保您没有破坏任何东西 - 您可以自由地组织课程的内部管道。

     

您的私有方法已经过测试,因为您所做的只是您已经测试过的重构行为。您永远不应该在私有方法未经测试或未经完全测试的情况下结束,因为只有在您看到清理公共方法实现的机会时才创建它们。这确保了私有方法的存在只是为了支持在测试期间必须调用它们的类,因为它们肯定是从公共方法调用的。

答案 6 :(得分:1)

轻松工作。脚步: 你有 - (NSString *)getTestString;在你的目标m文件中为接口Foo

  1. 在单元测试文件中添加一个类别:

    @interface DemoHomeViewController()    - (的NSString *)getTestString; @end

  2. 然后,做你想做的任何事。