Xcode 中私有方法的单元测试
我正在一个玩具项目中尝试测试驱动开发。 我可以让测试适用于我的类的公共接口(尽管我仍然持观望态度,因为我编写的测试代码比正在测试的方法中的测试代码多)。
我倾向于使用很多私有方法,因为我喜欢保持公共接口的干净; 但是,我仍然想对这些方法进行测试。
由于 Cocoa 是一种动态语言,我仍然可以调用这些私有方法,但我在测试中收到警告,我的类可能不会响应这些方法(尽管它显然会响应)。 因为我喜欢在没有警告的情况下进行编译,所以我的问题是:
- How do i close those warnings in Xcode?
- 我还可以采取其他措施来关闭这些警告吗?
- 我在尝试“白盒”测试时做错了什么吗?
I'm trying out test driven development in a toy project. I can get the tests working for the public interface to my classes (although I'm still on the fence because I'm writing more testing code than there is in the methods being tested).
I tend to use a lot of private methods becuase I like to keep the public interfaces clean; however, I'd still like to use tests on these methods.
Since Cocoa is a dynamic language, I can still call these private methods, but i get warnings in my tests that my class may not respond to these methods (although it clearly does). Since I like to compile with no warnings here are my questions:
- How do i turn off these warnings in Xcode?
- Is there something else I could do to turn off these warnings?
- Am I doing something wrong in trying 'white box' testing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
请记住,Objective-C 中实际上不存在“私有方法”之类的东西,这不仅仅是因为它是一种动态语言。 按照设计,Objective-C 具有 ivars 的可见性修饰符,但没有针对方法的可见性修饰符 — 您可以调用任何您喜欢的方法,这并非偶然。
@Peter的建议很好。 为了补充他的答案,我使用的另一种选择(当我不想/只需要私有方法的标头时)是在单元测试文件本身中声明一个类别。 (我使用
@interface MyClass (Test)
作为名称。)这是添加在发布代码中不必要的方法的好方法,例如用于访问被测试类具有的 ivars进入。 (当使用属性时,这显然不是一个问题。)我发现这种方法可以轻松公开和验证内部状态,以及添加仅测试方法。 例如,在这个单元测试文件中,我编写了一个< code>-isValid 方法用于验证二进制堆的正确性。 在生产中,这种方法会浪费空间,因为我假设堆是有效的 - 如果我修改代码,我只在测试单元测试回归时才关心它。
Remember that there's actually no such thing as "private methods" in Objective-C, and it's not just because it's a dynamic language. By design, Objective-C has visibility modifiers for ivars, but not for methods — it's not by accident that you can call any method you like.
@Peter's suggestion is a great one. To complement his answer, an alternative I've used (when I don't want/need a header just for private methods) is to declare a category in the unit test file itself. (I use
@interface MyClass (Test)
as the name.) This is a great way to add methods that would be unnecessary bloat in the release code, such as for accessing ivars that the class under test has access to. (This is obviously less of an issue when properties are used.)I've found this approach makes it easy to expose and verify internal state, as well as adding test-only methods. For example, in this unit test file, I wrote an
-isValid
method for verifying correctness of a binary heap. In production, this method would be a waste of space, since I assume a heap is valid — I only care about it when testing for unit test regressions if I modify the code.不。
不。
不。
解决方案是将您的私有方法移至其自己标头中的类别。 将此标头导入到实际类和测试用例类实现文件中。
Don't.
Don't.
No.
The solution is to move your private methods to a category in its own header. Import this header into both the real class and test-case class implementation files.
看起来另一个问题有答案: 有没有办法抑制Xcode 中出现警告?
Looks like another question has the answer: Is there a way to suppress warnings in Xcode?
几天前,当我开始使用 TDD 时,我也遇到了同样的问题。 我在 测试驱动的 iOS 开发 中发现了这个非常有趣的观点书:
I was dealing with the same issue when I started with TDD few days ago. I've found this very interesting point of view in Test-Driven iOS Development book:
虽然拥有私有标头或定义自己的类别可能是更正确的解决方案,但还有另一个非常简单的解决方案:在调用方法之前将对象强制转换为 (id)。
While having a private header or defining your own category are probably more correct solutions there is also another very simple solution: cast the object to (id) before calling the method.
如果您不想将私有方法实现分布在多个源文件中,则对类别解决方案的改进是定义一个扩展(本质上是一个匿名类别 - 请参阅 Apple 文档)位于由现有类的实现和相关单元导入的头文件中测试源文件。
如果主 @implementation 块中不存在私有方法的实现,则使用扩展可以让编译器发出警告。 此链接很好地说明了这一点。
If you don't want to distribute your private method implementations across multiple source files, a refinement to the Category solution is to define an Extension (essentially an anonymous Category - refer to Apple's documentation) in a header file that's imported by both your existing class' implementation and the relevant unit test source files.
Using an Extension allows the compiler to warn you if the implementation of the private method is not present in the main @implementation block. This link illustrates it nicely.
轻松的工作。 脚步:
1. 你有 -(NSString*)getTestString; 在接口 Foo 的目标 m 文件中
在单元测试文件中添加一个类别:
@interface DemoHomeViewController()
-(NSString*)getTestString;
@end
然后,现在就做任何你想做的事。
Easy Job. Steps:
1. You have -(NSString*)getTestString; in your target m file for interface Foo
Add a category in your unit test file:
@interface DemoHomeViewController()
-(NSString*)getTestString;
@end
Then, do anything you want now.